ARC 簡(jiǎn)明參考手冊(cè) (Part 1)

ARC 簡(jiǎn)明參考手冊(cè) (Part 1)

引言

在早期使用 Objective C 編程的時(shí)候, 需要手動(dòng)管理內(nèi)存, 對(duì)于初學(xué)者來(lái)說(shuō), 這是容易出錯(cuò)的。 后來(lái)蘋(píng)果在 Mac 平臺(tái)上引入了垃圾收集器的機(jī)制, 然而相對(duì)于 IOS 來(lái)說(shuō), 蘋(píng)果認(rèn)為垃圾收集會(huì)影響移動(dòng)設(shè)備性能, 于是提出了一個(gè)跨平臺(tái)的解決方案, ARC。 ARC 的原理是由編譯器推導(dǎo), 應(yīng)該在代碼中什么位置加入合適的語(yǔ)句來(lái)管理內(nèi)存, 這個(gè)過(guò)程是在編譯階段進(jìn)行的, 所以不會(huì)影響運(yùn)行時(shí)性能。 現(xiàn)在 ARC已然是蘋(píng)果標(biāo)準(zhǔn), 真可謂是對(duì)業(yè)界使用垃圾收集這個(gè)普遍標(biāo)準(zhǔn)的一次顛覆。

一個(gè)簡(jiǎn)單的例子

ARC 不是萬(wàn)能的, 它引入了一些隱形規(guī)則(這些規(guī)則會(huì)和我們的直覺(jué)有一定的沖突), 我們需要了解這些規(guī)則, 因?yàn)槲覀冊(cè)谀承┨貏e的情況下要干涉; 同時(shí)我們也要避免一些陷阱,這些陷阱其實(shí)是由于 ARC 的規(guī)則造成的坑。 也就是說(shuō), ARC有一定的學(xué)習(xí)曲線, 不像垃圾回收機(jī)制一樣, "it just works"。

我們先來(lái)看一個(gè)簡(jiǎn)單的例子, 下面相似的兩個(gè)代碼段在 ARC 模式下編譯運(yùn)行時(shí)沒(méi)有問(wèn)題的, 但是在非 ARC 模式下運(yùn)行的時(shí)候就會(huì)在 NSLog(@"count: %d", hello.val); 這里拋出 BAD_ACCESS 的錯(cuò)誤。 這是為什么呢?

ARC

MyClass *myclass() {
    MyClass* hello = [[MyClass alloc] init];
    return hello;
}

int main(int argc, const char * argv[]) {
    MyClass *hello;
    @autoreleasepool {
        hello = myclass();
    }
    NSLog(@"count: %d", hello.val);
    return 0;
}

非ARC

MyClass *myclass() {
    MyClass* hello = [[MyClass alloc] init];
    return [hello autorelease];
}

int main(int argc, const char * argv[]) {
    MyClass *hello;
    @autoreleasepool {
        hello = myclass();
        NSLog(@"reference count: %lu", [hello retainCount]);
    }
    NSLog(@"reference count: %lu", [hello retainCount]);
    NSLog(@"count: %d", hello.val);
    return 0;
}

因?yàn)樵?ARC 之前, local variable 是弱引用關(guān)系, 而在 ARC 之后則是強(qiáng)引用關(guān)系。 一開(kāi)始會(huì)覺(jué)得很別扭, 因?yàn)橹羔樈o我們的印象就應(yīng)該是弱引用, 不過(guò)話說(shuō)回來(lái), 我們不應(yīng)該先入為主的認(rèn)為 Objective C 的 * 和 C/C++ 的指針有半毛錢(qián)關(guān)系了 , 它就是代表一個(gè)引用, 就如同 Java/C# 中的引用。

所以大部分情況下, 我們就像 Java/C# 中那樣直接 "it just works" 的愉快的碼字就可以了, 無(wú)論是在 property 還是 local variable 的情況下, 默認(rèn)都是強(qiáng)引用。

but (這樣的故事通常都會(huì)有一個(gè) but), 由于 Objective C 是基于 Reference counting 的, 而 Java/C# 是基于 Tracing garbage collector 的, 這個(gè)本質(zhì)上的區(qū)別, 正是導(dǎo)致我們需要在寫(xiě) Objective C 代碼的 時(shí)候不能開(kāi)啟全自動(dòng)導(dǎo)航模式的原因。

從 Garbage collectors 說(shuō)起

<a href=http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Tracing_garbage_collectors"">Garbage collectors wiki</a>

自從 Lisp 引入垃圾回收機(jī)制以來(lái), 這個(gè)特性逐漸成為了高級(jí)語(yǔ)言的標(biāo)配。 垃圾回收器的實(shí)現(xiàn)機(jī)制分為兩種:

  • Tracing Garbage collectors

  • Reference counting

而由于 Reference counting 有一些明顯的短板:

  1. 循環(huán)引用

為了避免這個(gè)問(wèn)題, 需要復(fù)雜的算法來(lái)識(shí)別可以被回收的循環(huán)引用; 或者,讓程序員顯性說(shuō)明某個(gè)引用是 weak 的, 不影響垃圾回收。

  1. 需要額外的存儲(chǔ)空間(存放引用計(jì)數(shù))

  2. 代碼執(zhí)行速度的略微影響(多了增加/減少引用計(jì)數(shù)的語(yǔ)句)

  3. 原子性 (在多線程環(huán)境中要保證引用計(jì)數(shù)的原子性)。

所以大部分的垃圾回收器都是使用 Tracing Garbage collectors 的。

特別的, ARC 并不算是垃圾回收器, 不過(guò)它依賴于 Reference counting 的原理,所以也會(huì)遇到這些問(wèn)題。 就像一個(gè)懂事的小女孩,幫我們處理了很多繁瑣的工作,雖然她有點(diǎn)小迷糊, 有時(shí)候需要我們明確告訴她要怎么做,但是還是很惹人喜愛(ài)。

?烏賊娘
?烏賊娘
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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