OC內(nèi)存管理

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

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

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

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

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

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

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

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

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

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

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

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

id obj = [[NSObject alloc] init];

[obj autorelease];

[pool drain];

ARC的寫法:

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

注意:ARC對(duì)自動(dòng)釋放在運(yùn)行時(shí)做了一些優(yōu)化.一個(gè)對(duì)象原本應(yīng)注冊(cè)到自動(dòng)釋放池中,但是有些情況下經(jīng)ARC優(yōu)化后,這個(gè)對(duì)象就省略了自動(dòng)釋放池的注冊(cè).從而縮短了這個(gè)對(duì)象的生命周期.所以在ARC下,某個(gè)不以 alloc/new/copy/mutableCopy開頭的方法,返回的對(duì)象我們不應(yīng)該假定它就是在自動(dòng)釋放池中.
以下是Clang3.9文檔的說(shuō)明
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.
舉個(gè)例子:

- (void)viewDidLoad 
{
    [super viewDidLoad];

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容