前言:當您向一個對象發送一個autorelease消息時,Cocoa就會將該對象的一個引用放入到最新的自動釋放池。它仍然是個正當的對象,所以自動釋放池 定義的做用域內的其它對象能夠向它發送消息。當程序執行到做用域結束的位置時,自動釋放池就會被釋放,池中的全部對象也就被釋放。
1. ojc-c 是經過一種"referring counting"(引用計數)的方式來管理內存的, 對象在開始分配內存(alloc)的時候引用計數爲一,之後每當碰到有alloc,new,copy,retain的時候引用計數都會加一, 每當碰到release和autorelease的時候引用計數就會減一,若是此對象的計數變爲了0, 就會被系統銷燬.
2. NSAutoreleasePool 就是用來作引用計數的管理工做的,這個部分後面會詳細說到.
3. autorelease和release沒什麼區別,只是引用計數減一的時機不一樣而已,autorelease會在對象的使用真正結束的時候才作引用計數減一.
4.設定項目編譯環境爲ARC下時,編譯器會幫助咱們在程序的入口main函數就調用NSAutoreleasePool,這樣保證程序中不調用NSAutoreleasePool,但在退出時自動釋放
1.NSAutoreleasePool是什麼?
NSAutoreleasePool其實是個對象引用計數自動處理器,在官方文檔中被稱爲是一個類。html
NSAutoreleasePool能夠同時有多個,它的組織是個棧,老是存在一 個棧頂pool,也就是當前pool,每建立一個pool,就往棧裏壓一個,改變當前pool爲新建的pool,而後,每次給pool發送drain消 息,就彈出棧頂的pool,改當前pool爲棧裏的下一個 pool。
2.NSAutoreleasePool能夠用來作什麼,怎麼用?程序員
NSAutoreleasePool能夠在必定程度上幫助咱們蘋果開發程序員管理內存,讓咱們的工做更加嚴密,簡便。多線程
1)在ARC項目中,系統會自動幫助咱們在程序中嵌入NSAutoreleasePool,此爲蘋果公司程序員在寫這個編譯器的時候設定的;iphone
2)在MRC項目中,咱們須要本身去建立NSAutoreleasePool類對象去幫助咱們管理內存;異步
3)使用應注意:函數
a.在ARC項目中咱們一樣能夠建立NSAutoreleasePool類對象去幫助咱們更精確的管理內存問題。oop
b. NSAutoreleasePool的管理範圍是在NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];與[pool release];之間的對象測試
c..既然ARC項目中設置了ARC,爲何還要使用@autoreleasepool?(注意a的案例解釋)優化
ARC 並非捨棄了 @autoreleasepool
,而是在編譯階段幫你插入必要的 retain
/release
/autorelease
的代碼調用。spa
因此,跟你想象的不同,ARC 之下依然是延時釋放的,依然是依賴於 NSAutoreleasePool
,跟非 ARC 模式下手動調用那些函數本質上毫無差異,只是編譯 器來作會保證引用計數的正確性。
參考: Retain count semantics in ARC
4)使用例子:
例子1:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString* nsstring;
char* cstring = "Hello CString";
nsstring = [NSString stringWithUTF8String:cstring];
[pool release];(這一行代碼就是在給pool發送drain消息了)
官方API摘抄翻譯:
3.autorelease的原理是什麼?
Autorelease實際上只是把對release的調用延遲了,對於每個Autorelease,系統只是把該Object放入了當 前的Autorelease pool中,當該pool被釋放時,該pool中的全部Object會被調用Release。
4.!!!autorelease什麼時候釋放?
對於autorelease pool自己,會在以下兩個條件發生時候被釋放(詳細信息請參見第5條)
1)、手動釋放Autorelease pool
2)、Runloop結束後自動釋放
對於autorelease pool內部的對象在引用計數的retain == 0的時候釋放。release和autorelease pool 的 drain都會觸發retain--事件。
五、autorelease釋放的具體原理是什麼?
要搞懂具體原理,則要先要搞清楚autorelease什麼時候會建立。
咱們的程序在main()調用的時候會自動調用一個autorelease,而後在每個 Runloop, 系統會隱式建立一個Autorelease pool,這樣全部的release pool會構成一個象CallStack同樣的一個棧式結構,在每個Runloop結束時,當前棧頂的 Autorelease pool(main()裏的autorelease)會被銷燬,這樣這個pool裏的每一個Object會被release。
能夠把autorelease pool理解成一個相似父類與子類的關係,main()建立了父類,每一個Runloop自動生成的或者開發者自定義的autorelease pool都會成爲該父類的子類。當父類被釋放的時候,沒有被釋放的子類也會被釋放,這樣全部子類中的對象也會收到release消息。
那什麼是一個Runloop呢? 一個UI事件,Timer call, delegate call, 一個鼠標事件,鍵盤按下(MAC OSX),或者iphone上的觸摸事件,異步http鏈接下後當接收完數據時,都會是一個新的Runloop。
通常來講,消息循環運行一次是毫秒級甚至微秒級的,所以autorelease的效率仍然是很是高的,確實是一個巧妙的設計。
六、使用有什麼要注意的?
1)、NSAutoreleasePool能夠建立一個autorelease pool,但該對象自己也須要被釋放,如:
在引用計數環境下,使用[pool release]或[pool drain]效果是相同的,drain僅適用於max os高版本,低版本不適用,而release通用,其它並沒有太大差異。
2)、在ARC下,不能使用上述方式調用autorelease,而應當使用@autoreleasepool,如:
複製代碼
- @autoreleasepool {
- // Code benefitting from a local autorelease pool.
- }
3)、儘可能避免對大內存使用該方法,如圖片。對於這種延遲釋放機制,仍是儘可能少用,最好只用在方法內返回小塊內存申請地址值的狀況下,且參考和領會OC的一些系統方法,如:[NSString stringWithFormat:]。
4)、不要把大量循環操做放到同一個NSAutoreleasePool之間,這樣會形成內存峯值的上升。
七、關於多線程,有什麼要注意的?
我還未實際使用到,在官方API翻譯出相似以下語句:
1)、對於不一樣線程,應當建立本身的autorelease pool。若是應用長期存在,應該按期drain和建立新的autorelease pool
下面這句話摘自官方API,大概是說多線程中若是沒有使用到cocoa的相關調用,則不須要建立autorelease pool,我一直沒有理解透徹
If, however, your detached thread does not make Cocoa calls, you do not need to create an autorelease pool.
2)、若是不是使用的NSThread,就不要用aoturelease pool,除非你是多線程模式(multithreading mode) ,可使用NSThread的isMultiThreaded方法測試你的應用是不是多線程模式
PS:
我把它理解爲:新開線程最好實現NSAutoreleasePool(當 咱們點擊一個App中的一個按鈕或者其餘能夠觸碰開啓新業務的UI控件,在程序裏面就會自動開啓一條新線程,當咱們不用這個業務的時候,就須要程序幫咱們 提早在「程序的主窗口的全部代碼編譯結束後」以前關閉這條線程以優化線程的使用,必定程度上儘可能避免線程開啓太多佔用CPU嚴重引發的卡頓問題)(業務邏 輯處理-業務線程優化)
詳細能夠參考官方API的NSAutoreleasePool Class Reference