OC內(nèi)存管理

Objective-C提供三種內(nèi)存管理模型:

  1. 自動垃圾回收
  2. 手動引用計數(shù)MRC和自動釋放池.
  3. 自動引用計數(shù)ARC.

Objective-C 2.0 是支持自動垃圾回收機制的.但是iOS運行環(huán)境并不支持自動垃圾回收.而且自OS X 10.8及以后也已經(jīng)不推薦使用了,而是建議使用ARC.
在iOS5之前使用的是手動引用計數(shù)簡稱MRC.iOS5蘋果推出了自動引用計數(shù)ARC,并且推薦大家使用自動引用計數(shù)進行內(nèi)存管理.自動引用計數(shù)ARC就是讓編譯器來進行內(nèi)存管理,編譯器會在合適的地方幫你插入retain或release,因此不再需要手工輸入retain和release代碼了.(編譯時)
引用計數(shù)式內(nèi)存管理的思想是:

  1. 自己生成的對象,自己持有. 對應 alloc/new/copy/mutableCopy方法.
  2. 非自己生成的對象,自己也能持有. 通過調(diào)用retain方法,就能使自己持有.
  3. 不需要自己持有對象時,需要釋放. 通過調(diào)用release方法,釋放自己持有的對象.
  4. 不能釋放非自己持有的對象.

在這些思想的指導下,Cocoa 建立了一套明確的內(nèi)存管理的方法命名規(guī)則特笋,在編寫用于對象生成或持有的方法時,必須要遵守這些命名規(guī)則.以 alloc/new/copy/mutableCopy開頭的方法名意味著自己生成并持有對象.在ARC有效時,還要加一條命名規(guī)則:以init開頭的方法.注意以init開頭的方法的規(guī)則要比 alloc/new/copy/mutableCopy更嚴格.該方法必須是實例方法并且必須要返回對象.返回的對象應為id類型或instanceType.該返回的對象并不注冊到自動釋放池里去.基本上只是對alloc方法返回的對象進行初始化處理并返回該對象.
使用上述方法之外的方法取得的對象是自己不持有的對象,但該對象存在.(根據(jù)第四條:不能釋放非自己持有的對象.此時如果是MRC環(huán)境,就不能調(diào)用release方法進行釋放,否則崩潰.這種情況在MRC時經(jīng)常發(fā)生.比如UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];從該方法的命名可以看出,取得的對象是自己不持有的,所以如果你對[btn release]將導致奔潰.還有一種情況就是過度release.比如UIButton *btn = [[UIButton alloc] init]; [btn release]; [btn release];btn第一次release時,btn引用的對象就已經(jīng)被釋放了,btn這個指針變量已經(jīng)變成一個野指針了,如果再release,即是訪問這個野指針,這將導致崩潰.)

- (id)allocObject
{
        id obj = [[NSSObject alloc] init];
        return obj;
}
id obj1 = [obj0 allocObject]; //自己生成的對象自己持有
...
[obj1 release]; //所以這里使用完了,需要釋放.

以 alloc/new/copy/mutableCopy開頭的方法名意味著自己生成并持有對象.因此每次使用都需要時刻記住使用完后要釋放對象,但人往往會忘記釋放.如果某個方法能夠返回一個存在的對象,但該對象卻不需要我們自己去釋放,這將是一件多么讓人興奮的事!
那么如何返回一個存在但別人不持有的對象呢?
這就需要自動釋放池了.
自動釋放池( Autorelease Pool )提供了一個可以延遲給對象發(fā)送release消息的機制。它的使用場景比如從某方法返回一個對象時诉儒。給對象發(fā)送autorelease消息,那么該對象就被注冊到自動釋放池里面去了(這里需要注意的是如果給對象連續(xù)發(fā)送兩條autorelease消息,那么該對象會被注冊兩次,當池子drain時,該對象將被發(fā)送兩次release消息,這有可能導致過度release.),等到合適的時候自動釋放池會被發(fā)送drain消息,此時自動釋放池會給池子里面的每個對象都發(fā)送release消息,從而釋放掉對象.

- (id)object
{
        id obj = [[NSObject alloc] init];
        [obj autorelease]; 
        return obj;
}
id obj1 = [obj0 object]; //取得的對象存在,但自己不持有該對象.所以使用完后,不需要release.

如果想持有,則需發(fā)送retain消息.
[obj1 retain];//此時自己就持有了該對象,當不在需要持有時,你有義務釋放它.
...
[obj1 release];

dealloc是系統(tǒng)在對象被銷毀時自動調(diào)用的,不能手動調(diào)用!
如果重寫了dealloc方法,在MRC環(huán)境還需要調(diào)用[super dealloc](放在最后一句),但在ARC下禁止調(diào)用[super dealloc].

2.自動釋放池
自動釋放池( Autorelease Pool )提供了一個可以延遲給對象發(fā)送release消息的機制管怠。它的使用場景比如從某方法返回一個對象時淆衷。給對象發(fā)送autorelease消息,那么該對象就被注冊到自動釋放池里面去了,等到合適的時候自動釋放池會被發(fā)送drain消息,此時自動釋放池會給池子里面的每個對象都發(fā)送release消息,從而釋放掉對象.
這個"合適的時候"到底是什么時候呢?這就需要runloop了.iOS應用主線程的runloop(NSRunLoop)默認是開啟的.當事件發(fā)生時,runloop會處理事件,執(zhí)行我們寫的代碼.在處理事件之前,它會先創(chuàng)建好一個新的自動釋放池對象(NSAutoreleasePool對象),等到處理完這個事件時,runloop會銷毀這個NSAutoreleasePool對象,此時自動釋放池會給池子里面的每個對象都發(fā)送release消息,從而釋放掉對象.因此我們可以不用顯示創(chuàng)建一個自動釋放池.然而,在大量產(chǎn)生autorelease對象時,只要不廢棄NSAutoreleasePool對象,那么里面的對象就不能被釋放,這個時候就有可能產(chǎn)生內(nèi)存不足的情況.在這種情況下,有必要在適當?shù)牡胤缴?持有,廢棄NSAutoreleasePool對象.
MRC的寫法:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

id obj = [[NSObject alloc] init];

[obj autorelease];

[pool drain];

ARC的寫法:

@autoreleasepool
{
    id obj = [NSMutableArray array];
}//對象在這里被釋放,并銷毀.

注意:ARC對自動釋放在運行時做了一些優(yōu)化.一個對象原本應注冊到自動釋放池中,但是有些情況下經(jīng)ARC優(yōu)化后,這個對象就省略了自動釋放池的注冊.從而縮短了這個對象的生命周期.所以在ARC下,某個不以 alloc/new/copy/mutableCopy開頭的方法,返回的對象我們不應該假定它就是在自動釋放池中.
以下是Clang3.9文檔的說明
3.2.3 Unretained return values

A method or function which returns a retainable object type but does not return a retained value must ensure that the object is still valid across the return boundary.

When returning from such a function or method, ARC retains the value at the point of evaluation of the return statement, then leaves all local scopes, and then balances out the retain while ensuring that the value lives across the call boundary. In the worst case, this may involve an autorelease, but callers must not assume that the value is actually in the autorelease pool.

ARC performs no extra mandatory work on the caller side, although it may elect to do something to shorten the lifetime of the returned value.
舉個例子:

- (void)viewDidLoad 
{
    [super viewDidLoad];

    NSLog(@"--------");
    for (NSInteger i = 0; i < 100000000; i++)
    {
        People *p = [People productPeople];
    }
    NSLog(@"+++++++");
}

這段代碼在MRC下將導致內(nèi)存的急劇增長,并導致應用被系統(tǒng)直接干掉.
說明了-productPeople方法產(chǎn)生的autorelease對象由于自動釋放池沒被銷毀前它里面的對象也不會被釋放而導致內(nèi)存爆漲.
而在ARC下,由于ARC對自動釋放池有做優(yōu)化,所以并沒有引起內(nèi)存的太大變化.

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市渤弛,隨后出現(xiàn)的幾起案子祝拯,更是在濱河造成了極大的恐慌,老刑警劉巖她肯,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佳头,死亡現(xiàn)場離奇詭異,居然都是意外死亡晴氨,警方通過查閱死者的電腦和手機康嘉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來籽前,“玉大人亭珍,你說我怎么就攤上這事≈澹” “怎么了肄梨?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挠锥。 經(jīng)常有香客問我众羡,道長,這世上最難降的妖魔是什么蓖租? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任粱侣,我火速辦了婚禮辆毡,結果婚禮上,老公的妹妹穿的比我還像新娘甜害。我一直安慰自己舶掖,他們只是感情好,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布尔店。 她就那樣靜靜地躺著眨攘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嚣州。 梳的紋絲不亂的頭發(fā)上鲫售,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機與錄音该肴,去河邊找鬼情竹。 笑死,一個胖子當著我的面吹牛匀哄,可吹牛的內(nèi)容都是我干的秦效。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼涎嚼,長吁一口氣:“原來是場噩夢啊……” “哼阱州!你這毒婦竟也來了?” 一聲冷哼從身側響起法梯,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤苔货,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后立哑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夜惭,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年铛绰,在試婚紗的時候發(fā)現(xiàn)自己被綠了诈茧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡至耻,死狀恐怖若皱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尘颓,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布晦譬,位于F島的核電站疤苹,受9級特大地震影響,放射性物質發(fā)生泄漏敛腌。R本人自食惡果不足惜卧土,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一惫皱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尤莺,春花似錦旅敷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至友酱,卻和暖如春晴音,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缔杉。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工锤躁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人或详。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓系羞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霸琴。 傳聞我的和親對象是個殘疾皇子觉啊,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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

  • 今天看到一篇不錯的文章關于OC內(nèi)存管理的,轉載一下與你共享概述我們知道在程序運行過程中要創(chuàng)建大量的對象,和其他高級...
    niceSYT閱讀 452評論 0 2
  • 前言:本篇內(nèi)容假設您已經(jīng)對內(nèi)存管理有了基礎的理解沈贝。如retain杠人、release、autorelease宋下、auto...
    greatboygirl閱讀 673評論 0 3
  • ARC 一嗡善、簡介 在Objective-C中采用Automatic Reference Counting (ARC...
    伶俐ll閱讀 1,652評論 0 3
  • OC內(nèi)存管理一、基本原理(一)為什么要進行內(nèi)存管理学歧。由于移動設備的內(nèi)存極其有限罩引,所以每個APP所占的內(nèi)存也是有限制...
    ScaryMonsterLyn閱讀 516評論 0 3
  • OC內(nèi)存管理 一、基本原理 (一)為什么要進行內(nèi)存管理枝笨。 由于移動設備的內(nèi)存極其有限袁铐,所以每個APP所占的內(nèi)存也是...
    iOS_Developer閱讀 387評論 0 3