OC:內(nèi)存管理

目錄

  • 內(nèi)存管理原理
  • 自動(dòng)釋放池
  • 內(nèi)存管理原則

程序運(yùn)行過程中要?jiǎng)?chuàng)建大量的對(duì)象吩坝,OC中對(duì)象是存儲(chǔ)在堆中的,系統(tǒng)不會(huì)自動(dòng)釋放堆中的內(nèi)存。如果一個(gè)對(duì)象創(chuàng)建并使用后沒有得到及時(shí)釋放着憨,那么就會(huì)占用大量的內(nèi)存。

OC中基本類型是由系統(tǒng)進(jìn)行管理务嫡,放在棧上

在引入ARC(Automatic Reference Counting)自動(dòng)引用計(jì)數(shù)機(jī)制之前甲抖,OC的內(nèi)存管理需要由開發(fā)人員手動(dòng)維護(hù)。

在Xcode4.2之后的版本中??引入了ARC心铃,程序編譯時(shí)准谚,Xcode可以自動(dòng)為你的代碼添加內(nèi)存釋放代碼,如果編寫手動(dòng)釋放代碼Xcode會(huì)報(bào)錯(cuò)去扣,因此如果使用的Xcode4.2之后的版本柱衔,必須手動(dòng)關(guān)閉ARC,這樣才有助于我們理解OC的內(nèi)存管理機(jī)制愉棱。

為了理解OC的內(nèi)存管理機(jī)制唆铐,需要在Xcode中關(guān)閉ARC:項(xiàng)目屬性—Build Settings--搜索“garbage”找到Objective-C Automatic Reference Counting設(shè)置為No即可。


內(nèi)存管理原理

在C#中都有GC在自動(dòng)管理內(nèi)存奔滑,但是在OC中沒有垃圾回收機(jī)制艾岂,那么OC中內(nèi)存又是如何管理呢?其實(shí)在OC中內(nèi)存的管理是依賴對(duì)象引用計(jì)數(shù)器(reference counting)來進(jìn)行的朋其。

OC中每個(gè)對(duì)象都有一個(gè)與之對(duì)應(yīng)的整數(shù)王浴,叫“引用計(jì)數(shù)器”,當(dāng)一個(gè)對(duì)象在創(chuàng)建之后它的引用計(jì)數(shù)器值加1令宿,當(dāng)調(diào)用這個(gè)對(duì)象的alloc叼耙、retain、new粒没、copy方法之后引用計(jì)數(shù)器值自動(dòng)在原來的基礎(chǔ)上加1筛婉,當(dāng)調(diào)用這個(gè)對(duì)象的release方法之后它的引用計(jì)數(shù)器值減1,如果一個(gè)對(duì)象的引用計(jì)數(shù)器值為0,則系統(tǒng)會(huì)自動(dòng)調(diào)用這個(gè)對(duì)象的dealloc方法來銷毀這個(gè)對(duì)象爽撒。

下面通過代碼看一下引用計(jì)數(shù)器是如何工作的入蛆。
WZKPerson.h

#import <Foundation/Foundation.h>

@interface WZKPerson : NSObject
    @property(nonatomic,copy)NSString *name;
    @property(nonatomic,assign)NSInteger age;
@end

WZKPerson.m

#import "WZKPerson.h"

@implementation WZKPerson

-(void)dealloc
{
    self.name=nil;
    /*最后一定要調(diào)用父類的dealloc方法;
      目的:一是父類可能有其他引用對(duì)象需要釋放硕勿;二是當(dāng)前對(duì)象真正的釋放操作是在super的dealloc中完成的哨毁;
    */
    [super dealloc];
}
@end

main.m(部分代碼)

//調(diào)用alloc,引用計(jì)數(shù)+1
WZKPerson *personTest=[[WZKPerson alloc] init];
personTest.name=@"test";
personTest.age=30;

//輸出personTest對(duì)象的引用計(jì)數(shù)
NSLog(@"personTest的引用計(jì)數(shù):%lu",[personTest retainCount]);
//輸出結(jié)果:personTest的引用計(jì)數(shù):1

//執(zhí)行personTest的dealloc方法
//調(diào)用過release方法之后源武,personTest指向的對(duì)象就會(huì)被銷毀扼褪,但是此時(shí)變量personTest中還存放著WZKPerson對(duì)象的地址
[personTest release];

//如果不設(shè)置personTest=nil,則personTest就是一個(gè)野指針粱栖,它指向的內(nèi)存不屬于這個(gè)程序话浇,非常危險(xiǎn)
personTest=nil;

//如果不設(shè)置personTest=nil,此時(shí)再調(diào)用personTest的release方法會(huì)報(bào)錯(cuò)
//如果設(shè)置了personTest=nil闹究,此時(shí)personTest已經(jīng)是空指針了幔崖,則oc中給空指針發(fā)送消息是不會(huì)報(bào)錯(cuò)的
[personTest release];

WZKPerson *personTest2=[[WZKPerson alloc] init];
personTest2.name=@"test2";
personTest2.age=30;

//輸出結(jié)果:personTest的引用計(jì)數(shù):1
NSLog(@"personTest2的引用計(jì)數(shù):%lu",[personTest2 retainCount]);

//引用計(jì)數(shù)+1
[personTest2 retain];
//輸出結(jié)果:personTest的引用計(jì)數(shù):2
NSLog(@"personTest2的引用計(jì)數(shù):%lu",[personTest2 retainCount]);

//引用計(jì)數(shù)-1
[personTest2 release];
//輸出結(jié)果:personTest的引用計(jì)數(shù):1
NSLog(@"personTest2的引用計(jì)數(shù):%lu",[personTest2 retainCount]);

//執(zhí)行personTest2的dealloc方法
[personTest2 release];

personTest2=nil;

在上述代碼中,可以通過dealloc方法來查看是否一個(gè)對(duì)象已經(jīng)被回收渣淤,如果沒有回收赏寇,則有可能造成內(nèi)存泄漏。
如果一個(gè)對(duì)象被釋放后价认,那么最后引用它的變量需要手動(dòng)設(shè)置為nil嗅定,否則可能造成野指針錯(cuò)誤。

注意:OC中給空對(duì)象發(fā)送消息是不會(huì)引起錯(cuò)誤

自動(dòng)釋放池

在OC中存在著一種內(nèi)存自動(dòng)釋放機(jī)制叫做自動(dòng)釋放池(或自動(dòng)引用計(jì)數(shù))刻伊,但是與C#不同的是露戒,這僅僅是一種半自動(dòng)的機(jī)制,有些操作還是需要進(jìn)行手動(dòng)設(shè)置捶箱。

自動(dòng)內(nèi)存釋放使用@autoreleasepool關(guān)鍵字聲明一個(gè)代碼塊智什,如果一個(gè)對(duì)象在初始化時(shí)調(diào)用了autorelease方法,那么當(dāng)代碼塊執(zhí)行完之后丁屎,在塊中調(diào)用過autorelease方法的對(duì)象都會(huì)自動(dòng)調(diào)用一次release方法荠锭。

下面通過代碼來了解一下自動(dòng)釋放池。
WZKPerson.h

//構(gòu)造函數(shù)
-(WZKPerson *)initWithName:(NSString *)name age:(NSInteger)age;
//獲取對(duì)象的類方法
+(WZKPerson *)personWithName:(NSString *)name;

WZKPerson.m

-(WZKPerson *)initWithName:(NSString *)name age:(NSInteger)age
{
    self=[super init];
    if (self) {
        _name=[name copy];
        _age=age;
    }   
    return  self;
}

+(WZKPerson *)personWithName:(NSString *)name
{
    //這里調(diào)用了autorelease
    //OC類庫(kù)中的類方法一般都不需要手動(dòng)釋放晨川,內(nèi)部已經(jīng)調(diào)用了autorelease方法证九;
    WZKPerson *person=[[[WZKPerson alloc] init] autorelease];
    return person;
}

main.m(部分代碼)

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        WZKPerson *person1=[[WZKPerson alloc] init];
        //調(diào)用autorelease方法,后面就不需要手動(dòng)調(diào)用release方法了
        [person1 autorelease];
        //由于autorelease是延遲釋放(延遲到自動(dòng)釋放池銷毀)共虑,
        
        //所以這里仍然可以使用person1對(duì)象
        person1.name=@"Kevin";
    
        //調(diào)用autorelease方法
        WZKPerson *person2=[[[WZKPerson alloc] initWithName:@"Kevin" age:27] autorelease];
    
        //內(nèi)部已經(jīng)調(diào)用了autorelease愧怜,所以不需要手動(dòng)釋放
        //另外由于內(nèi)存管理原則慌核,在外部不使用alloc蕊爵、new、copy操作读处,
        //就不需要調(diào)用release或autorelease,所以這個(gè)操作是放到類方法內(nèi)部進(jìn)行完成
        WZKPerson *person3=[WZKPerson personWithName:@"Kevin"];
    }
    return 0;
}

下面我們對(duì)自動(dòng)內(nèi)存釋放稍作總結(jié):

  1. autorelease方法不會(huì)改變對(duì)象的引用計(jì)數(shù)器猜惋,只是將這個(gè)對(duì)象放到自動(dòng)釋放池中丸氛;
  2. 自動(dòng)釋放池實(shí)質(zhì)是當(dāng)自動(dòng)釋放池銷毀之后,調(diào)用release方法著摔,但是不一定能夠銷毀對(duì)象缓窜,例如:當(dāng)對(duì)象引用計(jì)數(shù)器值大于1時(shí),該對(duì)象就無法銷毀谍咆;
  3. 由于自動(dòng)釋放池最后統(tǒng)一銷毀對(duì)象禾锤,因此如果一個(gè)操作比較占用內(nèi)存,例如:對(duì)象較多或者對(duì)象占用資源較多摹察,最好不要放到自動(dòng)釋放池或者放到多個(gè)自動(dòng)釋放池时肿;
  4. OC中類庫(kù)的類方法一般都不需要手動(dòng)釋放,因?yàn)閮?nèi)部已經(jīng)調(diào)用了autorelease方法港粱;

內(nèi)存管理原則

關(guān)于內(nèi)存管理,總結(jié)起來可以用三條原則概括:

引用自《Objective-C基礎(chǔ)教程》第二版

  1. 使用new旦签、alloc查坪、copy方法創(chuàng)建一個(gè)對(duì)象時(shí),該對(duì)象的保留計(jì)數(shù)器值為1宁炫。當(dāng)不再使用該對(duì)象時(shí)偿曙,應(yīng)該向該對(duì)象發(fā)送一條release或autorelease消息。這樣該對(duì)象在其使用壽命結(jié)束時(shí)被銷毀羔巢;
  2. 當(dāng)你獲得一個(gè)對(duì)象時(shí)望忆,假設(shè)該對(duì)象的保留計(jì)數(shù)器值為1,而且已經(jīng)被設(shè)置為自動(dòng)釋放竿秆,那么你不需要執(zhí)行任何操作來確保該對(duì)象得到清理启摄。如果你打算在一段時(shí)間內(nèi)擁有該對(duì)象,則需要保留它并確保在操作完成時(shí)釋放它幽钢。
  3. 如果你保留了某個(gè)對(duì)象歉备,就需要(最終)釋放或自動(dòng)釋放該對(duì)象。必須保持retain方法和release方法的使用次數(shù)相等匪燕。

注:對(duì)象之間可能交叉引用蕾羊,此時(shí)需要遵循一個(gè)法則:誰創(chuàng)建,誰釋放

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末帽驯,一起剝皮案震驚了整個(gè)濱河市龟再,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌尼变,老刑警劉巖利凑,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡截碴,警方通過查閱死者的電腦和手機(jī)梳侨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來日丹,“玉大人走哺,你說我怎么就攤上這事≌芟海” “怎么了丙躏?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)束凑。 經(jīng)常有香客問我晒旅,道長(zhǎng),這世上最難降的妖魔是什么汪诉? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任废恋,我火速辦了婚禮,結(jié)果婚禮上扒寄,老公的妹妹穿的比我還像新娘鱼鼓。我一直安慰自己,他們只是感情好该编,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布迄本。 她就那樣靜靜地躺著,像睡著了一般课竣。 火紅的嫁衣襯著肌膚如雪嘉赎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天于樟,我揣著相機(jī)與錄音公条,去河邊找鬼。 笑死迂曲,一個(gè)胖子當(dāng)著我的面吹牛赃份,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奢米,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抓韩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了鬓长?” 一聲冷哼從身側(cè)響起谒拴,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涉波,沒想到半個(gè)月后英上,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炭序,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年苍日,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惭聂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡相恃,死狀恐怖辜纲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拦耐,我是刑警寧澤耕腾,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站杀糯,受9級(jí)特大地震影響扫俺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜固翰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一狼纬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骂际,春花似錦畸颅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涛癌。三九已至犯戏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拳话,已是汗流浹背先匪。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弃衍,地道東北人呀非。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像镜盯,于是被迫代替她去往敵國(guó)和親岸裙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 今天看到一篇不錯(cuò)的文章關(guān)于OC內(nèi)存管理的,轉(zhuǎn)載一下與你共享概述我們知道在程序運(yùn)行過程中要?jiǎng)?chuàng)建大量的對(duì)象速缆,和其他高級(jí)...
    niceSYT閱讀 451評(píng)論 0 2
  • ARC 一降允、簡(jiǎn)介 在Objective-C中采用Automatic Reference Counting (ARC...
    伶俐ll閱讀 1,649評(píng)論 0 3
  • OC內(nèi)存管理一、基本原理(一)為什么要進(jìn)行內(nèi)存管理艺糜。由于移動(dòng)設(shè)備的內(nèi)存極其有限剧董,所以每個(gè)APP所占的內(nèi)存也是有限制...
    ScaryMonsterLyn閱讀 514評(píng)論 0 3
  • OC內(nèi)存管理 一幢尚、基本原理 (一)為什么要進(jìn)行內(nèi)存管理。 由于移動(dòng)設(shè)備的內(nèi)存極其有限翅楼,所以每個(gè)APP所占的內(nèi)存也是...
    iOS_Developer閱讀 387評(píng)論 0 3
  • 前言:本篇內(nèi)容假設(shè)您已經(jīng)對(duì)內(nèi)存管理有了基礎(chǔ)的理解尉剩。如retain、release毅臊、autorelease理茎、auto...
    greatboygirl閱讀 671評(píng)論 0 3