int main(int argc, const char * argv[]) {
? ? ? ? @autoreleasepool {
? ? ? ? ? ? ? ? _objc_autoreleasePoolPrint();
? ? ? ? ? ? ? ? id array = [NSArray arrayWithObjects:@"d", nil];
? ? ? ? ? ? ? ? _objc_autoreleasePoolPrint();
? ? ? }
}
輸出如下:
##############
AUTORELEASE POOLS for thread 0x10007d000
1 releases pending.
[0x101800000]??................??PAGE??(hot) (cold)
[0x101800038]??################??POOL 0x101800038
##############
##############
AUTORELEASE POOLS for thread 0x10007d000
2 releases pending.
[0x101800000]??................??PAGE??(hot) (cold)
[0x101800038]??################??POOL 0x101800038
[0x101800040]???????0x100203950??__NSArrayI
##############
1 page和pool的關系丁屎,這里先說下正勒。將對象添加到自動釋放池噪窘,是將對象添加到page中,每一頁page的大小是固定的浊闪。一個自動釋放池中的對象可能很多,需要占據(jù)好幾頁page哎迄,也可能很少谭贪,只占據(jù)一頁page的一段,甚至可能好多page只占據(jù)了一頁令花。這都視自動釋放池中的對象多少而定阻桅。至于pool包含page還是page包含pool,我覺得怎么說都行兼都。
2 通過打印嫂沉,我們看到這里一頁page,pool只占據(jù)這頁page的一小部分扮碧,因為pool里面就一個對象输瓜。而這個自動釋放池是main函數(shù)中的創(chuàng)建的。在自動釋放池作用域(push->pop或{})中芬萍,所有發(fā)送autorelease消息的對象尤揣,統(tǒng)統(tǒng)加入到該釋放池。
3 自動釋放池還可以嵌套柬祠,對象添加自動釋放池添加到其前最后push的自動釋放池北戏。例如
int main(int argc, const char * argv[]) {
@autoreleasepool {
? ? ?_objc_autoreleasePoolPrint();
? ? ? ?@autoreleasepool {
? ? ? ? ? ? ? ?id array = [NSArray arrayWithObjects:@"d", nil];
? ? ? ? ? ? ? ?_objc_autoreleasePoolPrint(); ??
? ? ? ? }
? ? ? _objc_autoreleasePoolPrint();
}
##############
AUTORELEASE POOLS for thread 0x10007d000
1 releases pending.
[0x101800000]??................??PAGE??(hot) (cold)
[0x101800038]??################??POOL 0x101800038
##############
##############
AUTORELEASE POOLS for thread 0x10007d000
3 releases pending.
[0x101800000]??................??PAGE??(hot) (cold)
[0x101800038]??################??POOL 0x101800038
[0x101800040]??################??POOL 0x101800040
[0x101800048]???????0x1002003b0??__NSArrayI
##############
##############
AUTORELEASE POOLS for thread 0x10007d000
1 releases pending.
................??PAGE??(hot) (cold)
[0x101800038]??################??POOL 0x101800038
##############
嵌套的形式,原理后面會在后面詳細講到
4 當然沒有發(fā)送autoreleased消息的對象漫蛔,不會添加到自動釋放池
5 也證明了__autoreleasing修飾符與autorelease的等價嗜愈,因此ARC下,開發(fā)者可以使用該修飾符等價調(diào)用autorelease
說道NSAutoreleasePool莽龟,必然要講到RunLoop蠕嫁。這里先簡單提一下,在即將進入RunLoop時毯盈,創(chuàng)建自動釋放池剃毒,在準備進入休眠時,清空自動釋放池,然后創(chuàng)建新池赘阀。因此在主線程益缠,由于開啟了RunLoop,即使不手動創(chuàng)建自動釋放池基公,也有自動釋放池的存在幅慌,需要添加到自動釋放池的對象也有池可加,如果我們再根據(jù)需要創(chuàng)建自動釋放池轰豆,就類似自動釋放池的嵌套胰伍,我們可以選擇對象所添加的池子,控制release的時機酸休。子線程默認不開啟RunLoop骂租,因此我們需要手動添加自動釋放池。詳細的后面會講到(例如雨席,RunLoop清空和創(chuàng)建的是哪個池子)
手動內(nèi)存管理
簡單來說菩咨,只要遵循以下三點就可以在手動內(nèi)存管理中避免絕大部分的麻煩:
如果需要持有一個對象,那么對其發(fā)送retain
如果之后不再使用該對象陡厘,那么需要對其發(fā)送release(或者autorealse)
每一次對retain,alloc或者new的調(diào)用抽米,需要對應一次release或autorealse調(diào)用
Automatic Reference Counting,自動引用計數(shù)糙置,即ARC云茸,WWDC2011和iOS5所引入。ARC是LLVM 3.0編譯器的一項特性谤饭,使用ARC标捺,解決了iOS開發(fā)者手動內(nèi)存管理的麻煩。
ARC是Objective-C編譯器的特性揉抵,而不是運行時特性或者垃圾回收機制亡容,ARC所做的只不過是在代碼編譯時為你自動在合適的位置插入retain, release或autorelease,就如同之前MRC時你所做的那樣冤今。因此闺兢,至少在效率上ARC機制是不會比MRC弱的,而因為可以在最合適的地方完成引用計數(shù)的維護戏罢,以及部分優(yōu)化屋谭,使用ARC甚至能比MRC取得更高的運行效率。
MRC除了以上關鍵字之外龟糕,不會影響對象的引用計數(shù)桐磁。例如:
Person *p2 = p1; p2指向p1所指向的對象,但是對象的引用計數(shù)沒有改變讲岁,因為沒有出現(xiàn)上述關鍵字
這就是說我擂,我們需要不斷的重復上述關鍵字衬以,很是麻煩。ARC出現(xiàn)了扶踊!
ARC全程Automatic Reference Counting泄鹏,自動引用計數(shù)郎任。
ARC是LLVM 3.0起編譯器的一項特性秧耗,在編譯單位上,可以設置ARC有效無效舶治。例如我們可以設置整個Projiect的(Apple LLVM X.X - Language - Objective C -> Objective-C Automatic Reference Counting - YES)分井,也可以對單個文件可選擇開啟或禁止ARC(Build Phases - Compiler Flags???-fobjc-arc/-fno-objc-arc)
當我們開啟后,我們就不需要像之前那樣霉猛,顯式調(diào)用retain,release和autorelease尺锚。編譯器會在合適的位置替我們插入這些代碼。因此惜浅,還是引用計數(shù)瘫辩,只是內(nèi)存管理變成了編譯器的工作。
在MRC下坛悉,我們通過alloc/retain/copy/release/autorelease來分析引用計數(shù)伐厌,而在ARC下,我們通過強引用來分析引用計數(shù)(依據(jù)的標準不同了)
ARC下裸影,id類型和對象類型必須附加所有權修飾符挣轨。所有權修飾符有四種,__strong轩猩,__weak卷扮,__unsafe_unretained,__autoreleasing均践。id和對象類型在沒有明確指定所有權修飾符時晤锹,默認為__strong
Person *p1 = [[Person alloc] init]; ?等價于 ?Person __strong *p1 = [[Person alloc] init];
__strong修飾符表示對對象的強引用,持有強引用的變量p1在超出其作用域時被廢棄彤委,強引用失效
Person *p2 = p1;
NSLog(@"%d",_objc_rootRetainCount(p1)); //2
此時有兩個強引用
隨著持有強引用的變量超出作用域或者賦值指向其他對象鞭铆,對象的強引用都會隨之改變,引用計數(shù)也隨之改變)