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_retainautoreleasedreturnvalue
和objc_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記憶體管理的方方面面,包括物件的所有權與引用計數 自動釋放與便捷方法 訪問器方法與屬性 一些會改變引用計數的特殊...