記憶體管理 四 原始碼解讀所有權修飾符 一

2021-08-13 11:32:18 字數 4734 閱讀 2850

csdn

有道雲1. alloc/new/copy/mutablecopy

賦值給附有__strong修飾符的變數在實際的程式中到底是這麼樣執行的呢?

該原始碼實際上可以轉換為呼叫以下函式

id obj = objc_msgsend(nsobject, @selector(alloc));

objc_msgsend(obj, @selectro(init));

objc_release(obj);

2次呼叫了objc_msgsend方法, 變數作用域結束時通過objc_release釋放物件。雖然 arc 時不能使用release方法,但由此可知編譯器自動插入了release

2. alloc/new/copy/mutablecopy 之外

雖然呼叫了我們熟知的nsmutablearray類的array類方法,但得到的結果卻與之前稍有不同。

id obj = objc_msgsend(nsmutablearray, @selector(array));

objc_retainautoreleasedreturnvalue(obj);

objc_release(obj);

objc_retainautoreleasedreturnvalue 函式

objc_retainautoreleasedreturnvalue函式主要用於最優化程式執行。

顧名思義,它是用於自己持有物件的函式,但它持有的物件應該返回註冊在autoreleasepool中物件的方法,或者是函式的返回值。像這種,非alloc/new/copy/mutablecopy的方法,比如nsmutablearray類的array類方法等呼叫之後,由編譯器插入該函式。

這種objc_retainautoreleasedreturnvalue函式是成對的,與之相對的函式是objc_autoreleasereturnvalue

objc_autoreleasereturnvalue 函式

objc_autoreleasereturnvalue用於非alloc/new/copy/mutablecopy返回物件的實現上。

+ (id) array
原始碼如下, 呼叫看objc_autoreleasereturnvalue函式

+ (id) array
像該源**這樣,通過使用objc_autoreleasereturnvalue函式,返回註冊到autoreleasepool中的物件。

但是objc_autoreleasereturnvalue函式 與objc_autorelease函式不同,一般不僅限於註冊到autoreleasepool中。

objc_autoreleasereturnvalue函式會檢查使用該函式的方法或者函式呼叫方的執行命令列表,如果!!! 在方法或者函式的呼叫方在呼叫了方法或者函式後緊接著呼叫了objc_retainautoreleasedreturnvalue函式,那麼就不將返回的物件註冊到autoreleasepool中,而是直接傳遞到方法或者函式的呼叫方。

小結objc_retainautoreleasedreturnvalue函式與objc_retain函式不同,它即便不註冊到autoreleasepool中而返回物件,也能夠正確的獲取物件。

通過objc_retainautoreleasedreturnvalueobjc_autoreleasereturnvalue函式的協作,可以將物件不註冊到autoreleasepool中而直接傳遞, 這一過程到達了最優化。

就像前面我們看到的一樣,__wea修飾符提供的功能如同魔法一般。

這些功能就像魔法一樣,到底發生了什麼,我們一無所知。

假設變數obj附有__strong修飾符且物件被賦值.

id obj1;

objc_initweak(&obj1, obj);

objc_destroyweak(&obj1);

通過objc_initweak函式初始化附有__weak修飾符的變數。

在變數作用域結束時通過objc_destroyweak函式釋放該變數。

如下面**所示:

objc_initweak函式將附有__weak修飾符的變數obj1初始化為0後,會將賦值的物件obj作為引數呼叫objc_storeweak函式。

obj1 =0;

objc_storeweak(&obj1, obj);

objc_destroyweak函式將0做引數呼叫objc_storeweak函式

objc_storeweak

((&obj1, obj)

即使前面的原始碼和下面源**相同

id obj1;

obj1 = 0;

objc_storeweak(&obj1, obj);

objc_storeweak(&obj1, 0);

objc_storeweak 函式

objc_storeweak函式把第二引數的賦值物件的位址作為鍵值,將第乙個引數附有__weak修飾符的變數的位址註冊到weak表中。如果第二引數為0,則把變數的位址從weak表中刪除。(驗證我前面的理解)

weak表與引用計數表相同,作為雜湊表被實現。如果使用weak表,將廢棄物件的位址作為鍵值進行檢索,就能高效地獲取對應的附有__weak修飾符的變數的位址。另外,由於乙個物件可同時賦值給多個附有__weak修飾符的變數中,所以對於乙個鍵值,可註冊多個變數的位址。

釋放物件

釋放物件時,廢棄誰都不持有的物件的同時,程式的動作是怎樣的呢?下面我們來跟蹤觀察。物件將通過objc_release函式釋放。

(1) objc_release

(2) 因為引用計數為0所以執行 dealloc

(3) _objc_rootdealloc

(4) objc_dispose

(5) objc_destructinstance //銷毀例項

(6) objc_clear_deallocating //清除**

物件被廢棄時最後呼叫的objc_clear_deallocating函式的動作如下:

(1) 從 weak 表中獲取廢棄物件的位址為鍵值的紀錄。

(2) 將包含在記錄中的所有附有 __weak 修飾符變數的位址,賦值為nil。

(3) 從 weak 表中刪除該紀錄。

(4) 從引用計數表中刪除廢棄物件的位址為鍵值的紀錄。

根據以上步驟,前面說的如果附有__weak修飾符的變數所引用的物件被廢棄,則將nil值賦給該變數這一功能即被實現。由此可知如果有大量使用附有__weak修飾符的變數,則會消耗相應的cpu資源。良策是只在需要避免迴圈引用時使用__weak修飾符。

使用 __weak 修飾符的修飾自己生成並持有的物件

將自己生成並持有的物件賦值給附有__weak修飾符的變數,所以自己並不能持有該物件,這時會被釋放並被廢棄,因此會引起編譯器警告。

id obj ;

id tmp = objc_msgsend(nsobject, @selector(alloc));

objc_msgsend(tmp, @selector(init));

objc_initweak(&obj, tmp);

obj_release(tmp);

objc_destroyweak(&obj);

雖然自己生成並持有的物件通過objc_initweak函式被賦值給附有__weak修飾符的變數中,但編譯器判斷其並沒有持有者,故該物件立即通過objc_release函式被釋放和廢棄。

iOS記憶體管理和malloc原始碼解讀

在接觸ios開發的時候,我們都知道 引用計數 的概念,也知道arc和mrr,但其實這僅僅是對堆記憶體上物件的記憶體管理。用wwdc某session裡的話說,這其實只是記憶體管理的冰山一角。一般的iphone實際物理記憶體都在1g左右,對於超大的記憶體需求怎麼辦?其實也是和其它作業系統一樣的,都是由系...

iOS記憶體管理和malloc原始碼解讀

最近由於排查問題,順便對ios的記憶體管理,尤其是malloc庫稍微深入地了解一下,在這裡整理出來,和大家分享一下。在接觸ios開發的時候,我們都知道 引用計數 的概念,也知道arc和mrr,但其實這僅僅是對堆記憶體上物件的記憶體管理。用wwdc某session裡的話說,這其實只是記憶體管理的冰山一...

iOS記憶體管理系列之一 物件所有權與引用計數

記憶體管理是iphone或ipad開發中最為重要的一部分。掌握好了記憶體管理,開發出的應用就能執行流暢 掌握不好,開發出的東西就會效率低下,且容易崩潰。從本文開始,我將分幾次詳細介紹ios記憶體管理的方方面面,包括物件的所有權與引用計數 自動釋放與便捷方法 訪問器方法與屬性 一些會改變引用計數的特殊...