ARC下AutoReleasePool的誤區(qū)

寫這邊文章的原因是看到網(wǎng)絡(luò)上對(duì)于AutoReleasePool討論,發(fā)現(xiàn)大家對(duì)AutoReleasePool存在誤區(qū)。

AutoReleasePool 里面的對(duì)象何時(shí)釋放?

這個(gè)問題是常見的iOS面試題,錯(cuò)誤的答案:
1.等到一次runloop結(jié)束,AutoReleasePool被釋放時(shí)
2.超出作用域{}

這些答案都不對(duì),標(biāo)準(zhǔn)答案:
每次release時(shí)retainCount減一,當(dāng)retainCount為0時(shí)候釋放對(duì)象。release的時(shí)機(jī)比如runloop周期中AutoReleasePool被釋放時(shí),比如超出作用域時(shí)

關(guān)鍵概念點(diǎn):
1. 不是所有OC對(duì)象都會(huì)加入到AutoReleasePool
2. AutoReleasePool被釋放時(shí)里面的對(duì)象不一定會(huì)釋放,超出作用域一樣不一定會(huì)釋放

  1. 不是所有OC對(duì)象都會(huì)加入到AutoReleasePool
    AutoReleasePool是ARC的一部分,本質(zhì)上還是RC的機(jī)制,一個(gè)對(duì)象在ARC下,可能會(huì)被加入到autoreleasepool里面,也可能不會(huì)。比如被__autoreleasing標(biāo)記或者@autoreleasepool包裹的或者UIImage對(duì)象都會(huì)加入AutoReleasePool,其他的像只是單純創(chuàng)建NSObject是不會(huì),但是調(diào)用了NSObject的對(duì)象方法后是會(huì)加入AutoReleasePool的。
  1. AutoReleasePool被釋放時(shí)里面的對(duì)象不一定會(huì)釋放,超出作用域同樣的道理
    AutoReleasePool被釋放時(shí)里面的對(duì)象可能還有其他引用,所以AutoReleasePool被釋放時(shí)里面的對(duì)象只會(huì)執(zhí)行release操作,并不一定會(huì)釋放對(duì)象。
正常情況:
    __weak id objA = nil;
    {
        id objB = [NSObject new];
        objA = objB;
    }
    NSLog(@"%@", objA);
    // objA = null

這個(gè)是沒有異議的情況,objB出了作用域就會(huì)被釋放,但是下面的代碼就不一樣了

AutoReleasePool被釋放時(shí)有其他引用:
    id objA = nil;
    @autoreleasepool {
        id objB = [NSObject new];
        objA = objB;
    }
    NSLog(@"%@", objA);
    // objA = <NSObject: 0x600002708330>

objB雖然被加入到自動(dòng)釋放池,但是并不會(huì)被釋放掉,因?yàn)檫€有objA在強(qiáng)引用它。如果這里的objA是weak的,objB會(huì)被釋放

出了作用域但是AutoReleasePool沒有釋放:
    __weak id objA = nil;
    {
        __autoreleasing id objB = [NSObject new];
        objA = objB;
    }
    NSLog(@"%@", objA);
    // objA = <NSObject: 0x600000c545c0>

objA雖然是弱引用,但是__autoreleasing的AutoReleasePool是和objA同級(jí)的,要等AutoReleasePool釋放的時(shí)候objB才會(huì)被釋放,即使objB已經(jīng)出了作用域,其實(shí)這里出作用域的時(shí)候并沒有執(zhí)行release操作

AutoReleasePool釋放了,同時(shí)出了作用域,就會(huì)被釋放:
    __weak id objA = nil;
    {
        id objB = nil;
        @autoreleasepool {
            __autoreleasing NSObject *objC = [NSObject new];
            objB = objC;
        }
        objA = objB;
        NSLog(@"objA = %@", objA);
        //objA = <NSObject: 0x60000188c0c0>
    }
    NSLog(@"objA = %@", objA);
    //objA = null

源碼分析

autoreleasepool pop源碼:


image.png

release中的源碼:


image.png

總結(jié):

  1. 并不是所有對(duì)象都會(huì)被自動(dòng)加入到AutoReleasePool
  2. runloop周期結(jié)束的時(shí)候AutoReleasePool會(huì)被釋放
  3. AutoReleasePool被釋放時(shí)里面的對(duì)象會(huì)執(zhí)行release操作,但是并不一定會(huì)釋放
  4. AutoReleasePool里面的對(duì)象要等到retainCount為0時(shí)候釋放
  5. AutoReleasePool里面的對(duì)象出作用域的時(shí)候并不會(huì)立即執(zhí)行release操作
  6. for循環(huán)中的對(duì)象如果造成了內(nèi)存暴增,可以用@autoreleasepool 加入到臨時(shí)自動(dòng)釋放池
最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 如果你在 ARC 下感覺 @autoreleasepool 是個(gè)雞肋,那就錯(cuò)錯(cuò)啦 ?。?! @autorelease...
    Justin_W閱讀 684評(píng)論 0 1
  • 1. 用ARC管理內(nèi)存 ARC(Automatic ReferenceCounting, 自動(dòng)引用計(jì)數(shù))和iOS5...
    Icec閱讀 1,626評(píng)論 0 7
  • 作為iOS平臺(tái)的開發(fā)者,是否曾經(jīng)為內(nèi)存問題而苦惱過?內(nèi)存莫名的持續(xù)增長,程序莫名的crash,難以發(fā)現(xiàn)的內(nèi)存泄漏,...
    祥子_HelloWorld閱讀 462評(píng)論 0 1
  • MRC 對(duì)象持有討論 先看一個(gè)例子: 總結(jié):釋放非自己持有的對(duì)象會(huì)造成程序崩潰,因此絕不能釋放非自己持有的對(duì)象 關(guān)...
    金約21依代閱讀 466評(píng)論 0 1
  • 技 術(shù) 文 章 / 超 人 2019-03-20 補(bǔ)充@ dynamic與@ synthesize內(nèi)容 個(gè)人覺得要...
    樹下敲代碼的超人閱讀 19,473評(píng)論 24 120

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