問題:weak 底層實現(xiàn)原理

weak基本用法

weak是弱引用,用weak描述修飾或者所引用對象的計數(shù)器不會加一兑巾,并且會在引用的對象被釋放的時候自動被設(shè)置為nil,大大避免了野指針訪問壞內(nèi)存引起崩潰的情況忠荞,另外weak還可以用于解決循環(huán)引用蒋歌。

weak原理概括

weak表其實是一個hash(哈希)表,Key是所指對象的地址委煤,Value是weak指針的地址數(shù)組堂油。weak的底層實現(xiàn)的原理是什么?

Runtime維護(hù)了一個weak表素标,用于存儲指向某個對象的所有weak指針称诗。weak表其實是一個hash表,Key是所指對象的地址头遭,value是weak指針的地址(這個地址的值是所指對象指針的地址)數(shù)組寓免。
為什么value是數(shù)組?因為一個對象可能被多個弱引用指針指向

weak原理實現(xiàn)步驟

weak 的實現(xiàn)原理可概括三步:

  • 1计维、初始化時:runtime會調(diào)用objc_initWeak函數(shù)袜香,初始化一個新的weak指針指向?qū)ο蟮牡刂贰?/p>

    image
  • 2、添加引用時:objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù)鲫惶, objc_storeWeak() 的作用是更新指針指向蜈首,創(chuàng)建對應(yīng)的弱引用表。

image
  • 3、釋放時欢策,調(diào)用clearDeallocating函數(shù)吆寨。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil踩寇,最后把這個entry從weak表中刪除啄清,最后清理對象的記錄。

weak實現(xiàn)三步驟詳細(xì)過程:

  • 1俺孙、初始化時:runtime會調(diào)用objc_initWeak函數(shù)辣卒,objc_initWeak函數(shù)會初始化一個新的weak指針指向?qū)ο蟮牡刂贰?br> 示例代碼:
 NSObject *obj = [[NSObject alloc] init];
 id __weak obj1 = obj;

當(dāng)我們初始化一個weak變量時,runtime會調(diào)用 NSObject.mm 中的objc_initWeak函數(shù)睛榄。
這個函數(shù)在Clang中的聲明如下:
id objc_initWeak(id *object, id value);
而對于 objc_initWeak() 方法的實現(xiàn)如下:

// 查看對象實例是否有效,無效對象直接導(dǎo)致指針釋放
    if (!newObj) {
        *location = nil;
        return nil;
    }
    // 這里傳遞了三個 bool 數(shù)值
    // 使用 template 進(jìn)行常量參數(shù)傳遞是為了優(yōu)化性能
    return storeWeakfalse/*old*/, true/*new*/, true/*crash*/>
    (location, (objc_object*)newObj);
}

這里先判斷了其指針指向的類對象是否有效荣茫,無效直接釋放返回,不再往深層調(diào)用函數(shù)场靴。否則啡莉,object將通過bjc_storeWeak函數(shù)被注冊為一個指向value的__weak對象。

注意:objc_initWeak函數(shù)有一個前提條件:就是object必須是一個沒有被注冊為__weak對象的有效指針憎乙。而value則可以是null票罐,或者指向一個有效的對象叉趣。

  • 2泞边、添加引用時:objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù), objc_storeWeak() 的作用是更新指針指向疗杉,創(chuàng)建對應(yīng)的弱引用表阵谚。
    objc_storeWeak的函數(shù)聲明如下:
    id objc_storeWeak(id *location, id value);
    objc_storeWeak() 的具體實現(xiàn),請參考weak弱引用實現(xiàn)的方式,這里的實現(xiàn)很復(fù)雜烟具,沒看懂梢什,沒看懂。

  • 3朝聋、釋放時嗡午,調(diào)用clearDeallocating函數(shù)。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組冀痕,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil荔睹,最后把這個entry從weak表中刪除,最后清理對象的記錄言蛇。
    當(dāng)weak引用指向的對象被釋放時僻他,又是如何去處理weak指針的呢?當(dāng)釋放對象時腊尚,其基本流程如下:

1吨拗、調(diào)用objc_release
2、因為對象的引用計數(shù)為0,所以執(zhí)行dealloc
3劝篷、在dealloc中哨鸭,調(diào)用了_objc_rootDealloc函數(shù)
4、在_objc_rootDealloc中娇妓,調(diào)用了object_dispose函數(shù)
5兔跌、調(diào)用objc_destructInstance
6、最后調(diào)用objc_clear_deallocating,詳細(xì)過程如下:
   a. 從weak表中獲取廢棄對象的地址為鍵值的記錄
   b. 將包含在記錄中的所有附有 weak修飾符變量的地址峡蟋,賦值為   nil
   c. 將weak表中該記錄刪除
   d. 從引用計數(shù)表中刪除廢棄對象的地址為鍵值的記錄

拓展補(bǔ)充

weak坟桅,__unsafe_unretained, unowned 與 assign區(qū)別

  • __unsafe_unretained: 不會對對象進(jìn)行retain,當(dāng)對象銷毀時,會依然指向之前的內(nèi)存空間(野指針)

  • weak: 不會對對象進(jìn)行retain,當(dāng)對象銷毀時,會自動指向nil

  • assign: 實質(zhì)與__unsafe_unretained等同

  • unsafe_unretained也可以修飾代表簡單數(shù)據(jù)類型的property,weak也不能修飾用來代表簡單數(shù)據(jù)類型的property蕊蝗。

  • __unsafe_unretained 與 weak 比較仅乓,使用 weak 是有代價的,因為通過上面的原理可知蓬戚,__weak需要檢查對象是否已經(jīng)消亡夸楣,而為了知道是否已經(jīng)消亡,自然也需要一些信息去跟蹤對象的使用情況子漩。也正因此豫喧,__unsafe_unretained 比 __weak快,所以當(dāng)明確知道對象的生命期時,選擇__unsafe_unretained 會有一些性能提升幢泼,這種性能提升是很微小的紧显。但當(dāng)很清楚的情況下,__unsafe_unretained 也是安全的缕棵,自然能快一點是一點孵班。而當(dāng)情況不確定的時候,應(yīng)該優(yōu)先選用 __weak 招驴。

  • unowned使用在Swift中篙程,也會分 weak 和 unowned。unowned 的含義跟 __unsafe_unretained 差不多别厘。假如很明確的知道對象的生命期虱饿,也可以選擇 unowned。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末触趴,一起剝皮案震驚了整個濱河市氮发,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雕蔽,老刑警劉巖折柠,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異批狐,居然都是意外死亡扇售,警方通過查閱死者的電腦和手機(jī)前塔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來承冰,“玉大人华弓,你說我怎么就攤上這事±梗” “怎么了寂屏?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長娜搂。 經(jīng)常有香客問我迁霎,道長,這世上最難降的妖魔是什么百宇? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任考廉,我火速辦了婚禮,結(jié)果婚禮上携御,老公的妹妹穿的比我還像新娘昌粤。我一直安慰自己,他們只是感情好啄刹,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布涮坐。 她就那樣靜靜地躺著,像睡著了一般誓军。 火紅的嫁衣襯著肌膚如雪袱讹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天谭企,我揣著相機(jī)與錄音廓译,去河邊找鬼。 笑死债查,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓜挽。 我是一名探鬼主播盹廷,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼久橙!你這毒婦竟也來了俄占?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤淆衷,失蹤者是張志新(化名)和其女友劉穎缸榄,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祝拯,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡甚带,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年她肯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹰贵。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡晴氨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出碉输,到底是詐尸還是另有隱情籽前,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布敷钾,位于F島的核電站枝哄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏阻荒。R本人自食惡果不足惜膘格,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望财松。 院中可真熱鬧瘪贱,春花似錦、人聲如沸辆毡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舶掖。三九已至球昨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眨攘,已是汗流浹背主慰。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留鲫售,地道東北人共螺。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像情竹,于是被迫代替她去往敵國和親藐不。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容