ARC在Release與Debug模式中內存釋放的坑

以一個方法起頭:html

- (void)createCat {
    
    NSObject *cat = nil;
    if (!cat) {
        cat = [[NSObject alloc] init];
    
        //1
    }
    
    //2
}
複製代碼

當調用 createObject 方法, object 對象會在何時釋放? 我猜大部分人會回答在位置2釋放. 從語法層面解釋也比較容易, 局部變量在做用域內默認是 strong 的, 因此出了做用域局部變量纔會釋放.bash

而如果咱們在位置2增長 log, 也很容易證明這一點, 的確在位置2的時候沒有釋放.app

然而實際狀況並無這麼簡單, 從現象看來用薛定諤的貓比喻比較恰當: 當你在觀察它, 它就是活的, 當你不觀察他, 它已經死了.優化

固然咱們的觀察是"直接"打印它. 但何時代碼變成玄學了? 看到這裏你確定認爲博主在胡謅, 下面作個試驗: 咱們建立一個 weak 修飾的 property, 當建立一個 cat 後, 讓這個 property 指向這個 cat. 咱們經過 log 這個 weak property 間接"觀察"它有沒有死.spa

//_catWeakProperty 爲 weak property
- (void)createCat {
    
    NSObject *cat = nil;
    if (!_catWeakProperty) {
        cat = [[NSObject alloc] init];
        _catWeakProperty = cat;
    }
    
    NSLog(@"cat: %@", _catWeakProperty);
    //NSLog(@"cat: %@", cat);
}
複製代碼

運行起來, 沒錯, 打印出來的 cat 真的是 nil, 已經釋放, 但你將下一行註釋打開, 直接 log 這個對象, 它又並無釋放.code

看到這裏是否是以爲很沒有道理, 實際上是仍是有道理的, 上面沒有說清楚運行環境: 這些代碼只有在 ARC ==Release== 環境中才會是這種效果, 若是在 Debug 環境中, 不管如何這個對象不管如何都不會釋放. 若是在網上搜 Debug 和 Release 的相關不一樣, 會發現不少博客都有說 Debug 環境內存會延遲釋放, 而 Release 環境內存達到釋放時機會當即釋放. 這樣說也沒毛病, 實際按蘋果官方的說法這只是 ARC 環境中運行時的一些優化, 但具體優化策略蘋果是不會告訴你的...htm

Is ARC slow?對象

It depends on what you’re measuring, but generally 「no.」 The compiler efficiently eliminates many extraneous retain/release calls and much effort has been invested in speeding up the Objective-C runtime in general. In particular, the common 「return a retain/autoreleased object」 pattern is much faster and does not actually put the object into the autorelease pool, when the caller of the method is ARC code.內存

-- Transitioning to ARC Release Notesci

這種狀況很是特殊, 必須是 weak property(__weak 不會優化), 局部變量的生成在其餘的做用域, ARC/Release 環境纔會有這樣的優化, 這也算是蘋果的又一個坑吧, 記錄一下, 之後查問題能夠留個心眼.

相關文章
相關標籤/搜索