參考書籍:《精通objective-c》【美】 keith lee
<a href="#%e7%b2%be%e9%80%9aobjective-c%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86">精通objective-c記憶體管理</a>
<a href="#%e7%9b%ae%e5%bd%95">目錄</a>
<a href="#%e7%a8%8b%e5%ba%8f%e7%9a%84%e5%86%85%e5%ad%98%e4%bd%bf%e7%94%a8%e6%83%85%e5%86%b5">程式的記憶體使用情況</a>
<a href="#%e6%89%8b%e5%8a%a8%e7%ae%a1%e7%90%86">手動管理</a>
<a href="#mrr%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%e5%9f%ba%e6%9c%ac%e5%8e%9f%e5%88%99">mrr記憶體管理基本原則</a>
<a href="#%e4%bd%bf%e7%94%a8mrr">使用mrr</a>
<a href="#%e8%87%aa%e5%8a%a8%e5%bc%95%e7%94%a8%e8%ae%a1%e6%95%b0">自動引用計數</a>
<a href="#arc%e8%a7%84%e5%88%99%e5%92%8c%e7%ba%a6%e5%ae%9a">arc規則和約定</a>
<a href="#%e4%bd%bf%e7%94%a8arc">使用arc</a>
<a href="#%e5%a4%84%e7%90%86%e5%be%aa%e7%8e%af%e5%bc%95%e7%94%a8">處理循環引用</a>
objective-c可執行程式是由(可執行)代碼、初始化和未初始化的程式資料、連結資訊、重定位資訊、局部資料和動态資料構成的。
程式資料包括以靜态方式聲明的變量和程式常量(即在程式編譯時在代碼中設定的常數)。可執行代碼、程式資料以及連結和重定位資訊會以靜态方式被配置設定記憶體,并在程式的生命周期一直存在。
局部(自動)資料在語句塊中聲明并且僅在該語句塊中有效,當該語句塊執行後局部資料不會繼續存在。從文法方面講,objective-c的符合語句塊就是由括号封裝的語句集合。自動資料被存儲在程式棧中,程式棧通常是在執行程式/線程前就被設定尺寸的記憶體段。棧用于存儲局部變量和調用方法/函數的上下文資料,以及調用完方法後繼續執行程式的代碼位址,作業系統會自動管理這些記憶體,這些資料會獲得棧中的記憶體,而配置設定給這些資料的記憶體會在它們失效後被釋放。
在運作時,objective-c會将建立的對象(通過nsobject類的alloc方法)存儲在動态配置設定的記憶體即堆記憶體中。以動态方式建立對象就意味着需要進行記憶體管理,因為在堆記憶體中建立的對象永遠不會超出其作用範圍。

不進行記憶體管理和錯誤的記憶體管理通常會導緻以下結果:
記憶體洩漏:如果程式沒有釋放不再使用的對象,就會導緻出現該問題。如果程式沒有使用為其配置設定的記憶體,就會浪費記憶體資源;如果系統繼續為程式配置設定記憶體并且沒有釋放這些記憶體,程式最終會耗盡系統記憶體。
懸挂指針:如果程式釋放了仍在使用的對象,就會導緻該問題。如果将來程式嘗試通路這些對象,就會出現程式錯誤。
objective-c的記憶體管理是通過引用計數實作的,引用計數是一種通過對象的唯一引用,确定對象是否正在被使用的技術。如果對象的引用計數降到了0,對象就會被視為不再有用,而且運作時系統會釋放它的記憶體。objective-c開發環境提供了兩種記憶體管理機制:手動管理(mrr)和自動引用技術(arc)。
objective-c對象是通過指向objective-c對象記憶體位址的變量(即指針),以間接方式通路的。對象指針實作了objective-c對象的通路功能,但是它們本身不能管理所有權。
1.為建立的所有對象設定所有權
2.應使用retain方法擷取對象(你尚未擁有)的所有權
3.當不再使用某個對象時,必須放棄其所有權
4.不能放棄不歸你所有的對象的所有權
也可以通過autorelease方法延遲釋放操作
下面開發一個簡單的示例程式,程式共包含3個類:orderentry類,orderitem類和address類。其中每個orderentry對象都擁有一個相應的orderitem對象和address對象。
首先需要建立一個新工程,在設定工程存儲位置時,取消勾選source control複選框,由于xcode 6之後的版本,工程都是預設使用arc,完成建立後,需要在下圖所示位置進行修改,取消使用arc。
首先是address類,接口部分不用編輯
address.m
下面是orderitem類
orderitem.h
orderitem.m
最後是orderentry類
orderentry.h
orderentry.m
在main.m中測試
運作結果:
如上述結果所示,所有對象的建立/保留和釋放消息都達到了平衡,如果你要確定程式沒有記憶體洩漏,可以使用product菜單中的analyze工具進行檢測,如果把<code>[orderid release];</code>注釋掉就會檢測到潛在的記憶體洩漏問題。
arc可以為objective-c對象和塊提供自動記憶體管理功能,是蘋果公司推薦使用的記憶體管理方式。
1.不能手動編寫發送retain、retaincount、release、autorelease和dealloc消息的代碼。arc會在編譯時根據需要自動插入這些消息。arc會在你編寫的類(沒有編寫dealloc方法的情況)中自動建立dealloc方法,釋放起擁有的對象并在dealloc方法中調用父類的dealloc方法。
2.不能直接進行id和(void*)類型的互轉,arc隻能管理objective-c對象和塊,不能使用c結構中的對象指針。
3.需要使用自動釋放池代碼塊執行由arc管理的自動釋放操作
4.不能使用記憶體區(nszone)以及相關的架構函數。
5.為了和非arc代碼合作,不能建立以copy開頭的方法和自動聲明屬性
arc的聲明周期限定符
下面開發一個簡單的示例程式,程式同樣地共包含3個類:orderentry類,orderitem類和address類。其中每個orderentry對象都擁有一個相應的orderitem對象和address對象。
由于xcode 6之後的版本,工程都是預設使用arc,不再需要其它額外操作。
下面是3個類的實作檔案,由于接口檔案與使用mrr時完全一樣,就不再寫出
可以看到3個類的實作部分與使用mrr時也都大同小異,隻是去掉了所有的retain、release消息的發送和[super dealloc]調用父類的dealloc方法(因為arc會自動調用)。
運作結果
相比mrr,arc簡化了大量代碼
arc無法自動處理循環引用,假設orderentry對象擁有一個orderitem執行個體變量且orderitem對象擁有一個orderentry執行個體變量,預設情況都是強引用,就會在這兩個對象之間造成循環引用。兩個對象永遠都不會被釋放,因而導緻記憶體洩漏。這種問題可以用弱引用解決沒被弱引用的對象不屬于引用它的對象,進而可以消除循環引用。蘋果公司約定,父對象強引用其所有的子對象,子對象弱引用其父對象(如果有必要)。