国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【iOS】weak關鍵字的實現(xiàn)原理

這篇具有很好參考價值的文章主要介紹了【iOS】weak關鍵字的實現(xiàn)原理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

關于什么是weak關鍵字可以去看看我以前的一篇博客:【OC】 屬性關鍵字

weak原理

1. SideTable

SideTable 這個結構體,前輩給它總結了一個很形象的名字叫引用計數(shù)和弱引用依賴表,因為它主要用于管理對象的引用計數(shù)和 weak 表。在 NSObject.mm 中聲明其數(shù)據(jù)結構:

struct SideTable {
   
// 保證原子操作的自旋鎖
    spinlock_t slock;
    // 引用計數(shù)的 hash 表
    RefcountMap refcnts;
    // weak 引用全局 hash 表
    weak_table_t weak_table;
    
    SideTable() {
   
        memset(&weak_table, 0, sizeof(weak_table));
    }

    ~SideTable() {
   
        _objc_fatal("Do not delete SideTable.");
    }

    void lock() {
    slock.lock(); }
    void unlock() {
    slock.unlock(); }
    void reset() {
    slock.reset(); }

    // Address-ordered lock discipline for a pair of side tables.

    template<HaveOld, HaveNew>
    static void lockTwo(SideTable *lock1, SideTable *lock2);
    template<HaveOld, HaveNew>
    static void unlockTwo(SideTable *lock1, SideTable *lock2);
}

slock是為了防止競爭選擇的自旋鎖
refcnts 是協(xié)助對象的 isa 指針的 extra_rc 共同引用計數(shù)的變量(對于對象結果,在后文提到)

接著我們來看一下SideTable中的這三個成員變量:

1.1 spinlock_t slock 自旋鎖

自旋鎖的效率高于互斥鎖。但是我們要注意由于自旋時不釋放CPU,因而持有自旋鎖的線程應該盡快釋放自旋鎖,否則等待該自旋鎖的線程會一直在哪里自旋,這就會浪費CPU時間。

在操作引用計數(shù)的時候?qū)ideTable加鎖,避免數(shù)據(jù)錯誤。

1.2 RefcountMap

【iOS】weak關鍵字的實現(xiàn)原理,ios

typedef objc::DenseMap<DisguisedPtr<objc_object>,size_t,true> RefcountMap;

其中DenseMap 又是一個模板類:

template<typename KeyT, typename ValueT,
         bool ZeroValuesArePurgeable = false, 
         typename KeyInfoT = DenseMapInfo<KeyT> >
class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, 
  ZeroValuesArePurgeable, KeyInfoT>, KeyT, ValueT, KeyInfoT, 
  ZeroValuesArePurgeable> {
   
  ...
  BucketT *Buckets;
  unsigned NumEntries;
  unsigned NumTombstones;
  unsigned NumBuckets;
  ...
}

比較重要的成員有這幾個:

1.ZeroValuesArePurgeable 默認值是 false, 但 RefcountMap 指定其初始化為 true。 這個成員標記是否可以使用值為 0 (引用計數(shù)為 1) 的桶. 因為空桶存的初始值就是 0, 所以值為 0 的桶和空桶沒什么區(qū)別.。如果允許使用值為 0 的桶, 查找桶時如果沒有找到對象對應的桶, 也沒有找到墓碑桶, 就會優(yōu)先使用值為 0 的桶。
2.Buckets 指針管理一段連續(xù)內(nèi)存空間, 也就是數(shù)組, 數(shù)組成員是 BucketT 類型的對象, 我們這里將 BucketT 對象稱為桶(實際上這個數(shù)組才應該叫桶, 蘋果把數(shù)組中的元素稱為桶應該是為了形象一些, 而不是哈希桶中的桶的意思)。桶數(shù)組在申請空間后, 會進行初始化, 在所有位置上都放上空桶(桶的 keyEmptyKey 時是空桶), 之后對引用計數(shù)的操作, 都要依賴于桶。
桶的數(shù)據(jù)類型實際上是 std::pair, 類似于 swift 中的元祖類型, 就是將對象地址和對象的引用計數(shù)(這里的引用計數(shù)類似于isa, 也是使用其中的幾個 bit 來保存引用計數(shù), 留出幾個 bit 來做其它標記位)組合成一個數(shù)據(jù)類型。

BucketT 的定義如下:

typedef std::pair<KeyT, ValueT> BucketT;

3.NumEntries 記錄數(shù)組中已使用的非空的桶的個數(shù).

4.NumTombstones, Tombstone 直譯為墓碑, 當一個對象的引用計數(shù)為0, 要從桶中取出時, 其所處的位置會被標記為 Tombstone. NumTombstones 就是數(shù)組中的墓碑的個數(shù). 后面會介紹到墓碑的作用.

5.NumBuckets 桶的數(shù)量, 因為數(shù)組中始終都充滿桶, 所以可以理解為數(shù)組大小.

inline uint64_t NextPowerOf2(uint64_t A) {
   
    A |= (A >> 1);
    A |= (A >> 2);
    A |= (A >> 4);
    A |= (A >> 8);
    A |= (A >> 16);
    A |= (A >> 32);
    return A + 1;
}

這是對應 64 位的提供數(shù)組大小的方法, 需要為桶數(shù)組開辟空間時, 會由這個方法來決定數(shù)組大小. 這個算法可以做到把最高位的 1 覆蓋到所有低位. 例如 A = 0b10000, (A >> 1) = 0b01000, 按位與就會得到 A = 0b11000, 這個時候 (A >> 2) = 0b00110, 按位與就會得到 A = 0b11110. 以此類推 A 的最高位的 1, 會一直覆蓋到高 2 位、高 4 位、高 8 位, 直到最低位. 最后這個充滿 1 的二進制數(shù)會再加 1, 得到一個 0b1000…(N 個 0). 也就是說, 桶數(shù)組的大小會是 2^n.

RefcountMap 的工作邏輯
1.通過計算對象地址的哈希值, 來從 SideTables 中獲取對應的 SideTable. 哈希值重復的對象的引用計數(shù)存儲在同一個 SideTable 里.
2.SideTable 使用 find() 方法和重載 [] 運算符的方式, 通過對象地址來確定對象對應的桶. 最終執(zhí)行到的查找算法是 LookupBucketFor().
3.查找算法會先對桶的個數(shù)進行判斷, 如果桶數(shù)為 0 則 return false 回上一級調(diào)用插入方法. 如果查找算法找到空桶或者墓碑桶, 同樣 return false 回上一級調(diào)用插入算法, 不過會先記錄下找到的桶. 如果找到了對象對應的桶, 只需要對其引用計數(shù) + 1 或者 - 1. 如果引用計數(shù)為 0 需要銷毀對象, 就將這個桶中的 key 設置為 TombstoneKey

value_type& FindAndConstruct(const KeyT &Key) {
   
    BucketT *TheBucket;
    if (LookupBucketFor(Key, TheBucket))
      return *TheBucket;
    return *InsertIntoBucket(Key, ValueT(), TheBucket);
  }

4.插入算法會先查看可用量, 如果哈希表的可用量(墓碑桶+空桶的數(shù)量)小于 1/4, 則需要為表重新開辟更大的空間, 如果表中的空桶位置少于 1/8 (說明墓碑桶過多), 則需要清理表中的墓碑. 以上兩種情況下哈希查找算法會很難查找正確位置, 甚至可能會產(chǎn)生死循環(huán), 所以要先處理表, 處理表之后還會重新分配所有桶的位置, 之后重新查找當前對象的可用位置并插入. 如果沒有發(fā)生以上兩種情況, 就直接把新的對象的引用計數(shù)放入調(diào)用者提供的桶里.

【iOS】weak關鍵字的實現(xiàn)原理,ios

墓碑的作用:

  1. 如果 c 對象銷毀后將下標 2 的桶設置為空桶而不置為墓碑桶的話, 此時為 e 對象增加引用計數(shù), 根據(jù)哈希算法查找到下標為 2 的桶時, 就會直接插入, 無法為已經(jīng)在下標為 4 的桶中的 e 增加引用計數(shù),但是我們正常的流程中c 對象銷毀后下標 2的桶將會被置為墓碑桶,這樣的話,在對e對象增加引用計數(shù)的時候,根據(jù)哈希算法找到下標為2的桶時,就會將2跳過,往后繼續(xù)查找,直至找到e對象所對應的桶為止,或者直至找到空桶新建一個存e對象的桶
  2. 如果此時初始化了一個新的對象 f, 根據(jù)哈希算法查找到下標為 2 的桶時發(fā)現(xiàn)桶中放置了墓碑, 此時會記錄下來下標 2. 接下來繼續(xù)哈希算法查找位置, 查找到空桶時, 就證明表中沒有對象 f, 此時 f 使用記錄好的下標 2 的墓碑桶而不是查找到的空桶, 就可以利用到已經(jīng)釋放的位置,保證哈希表中前面部分都是被利用或者待利用的狀態(tài)。

查找某對象對應桶的源碼如下:

bool LookupBucketFor(const LookupKeyT &Val,
                       const BucketT *&FoundBucket) const {
   
    ...
    if (NumBuckets == 0) {
    //桶數(shù)是0
      FoundBucket = 0;
      return false; //返回 false 回上層調(diào)用添加函數(shù)
    }
    ...
    unsigned BucketNo = getHashValue(Val) & (NumBuckets-1); //將哈希值與數(shù)組最大下標按位與
    unsigned ProbeAmt = 1; //哈希值重復的對象需要靠它來重新尋找位置
    while (1) {
   
      const BucketT *ThisBucket = BucketsPtr + BucketNo; //頭指針 + 下標, 類似于數(shù)組取值
      //找到的桶中的 key 和對象地址相等, 則是找到
      if (KeyInfoT::isEqual(Val, ThisBucket->first)) {
   
        FoundBucket = ThisBucket;
        return true;
      }
      //找到的桶中的 key 是空桶占位符, 則表示可插入
      if (KeyInfoT::isEqual(ThisBucket->first, EmptyKey)) {
    
        if (FoundTombstone) ThisBucket = FoundTombstone; //如果曾遇到墓碑, 則使用墓碑的位置
        FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
        return false; //找到空占位符, 則表明表中沒有已經(jīng)插入了該對象的桶
      }
      //如果找到了墓碑
      if (KeyInfoT::isEqual(ThisBucket->first, TombstoneKey) && !FoundTombstone)
        FoundTombstone = ThisBucket;  // 記錄下墓碑
      //這里涉及到最初定義 typedef objc::DenseMap<DisguisedPtr<objc_object>,size_t,true> RefcountMap, 傳入的第三個參數(shù) true
      //這個參數(shù)代表是否可以清除 0 值, 也就是說這個參數(shù)為 true 并且沒有墓碑的時候, 會記錄下找到的 value 為 0 的桶
      if (ZeroValuesArePurgeable  && 
          ThisBucket->second == 0  &&  !FoundTombstone) 
        FoundTombstone = ThisBucket;

      //用于計數(shù)的 ProbeAmt 如果大于了數(shù)組容量, 就會拋出異常
      if (ProbeAmt > NumBuckets) {
   
          _objc_fatal("...");
      }
      BucketNo += ProbeAmt++; //本次哈希計算得出的下表不符合, 則利用 ProbeAmt 尋找下一個下標
      BucketNo&= (NumBuckets-1); //得到新的數(shù)字和數(shù)組下標最大值按位與
    }
  }

向某對象的引用計數(shù)桶插入代碼如下:文章來源地址http://www.zghlxwxcb.cn/news/detail-604928.html

BucketT *InsertIntoBucketImpl(const KeyT &

到了這里,關于【iOS】weak關鍵字的實現(xiàn)原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • volatile關鍵字原理的使用介紹和底層原理解析和使用實例

    volatile 的主要作用是保證可見性和有序性,禁止編譯器優(yōu)化。 保證可見性:當一個變量被聲明為 volatile 之后,每次讀取這個變量的值都會從主內(nèi)存中讀取,而不是從緩存中讀取,這就保證了不同線程對這個變量操作的可見性。 有序性:volatile 保證了不同線程對一個 vo

    2024年02月02日
    瀏覽(22)
  • 線程中并發(fā)安全問題(Sychronized關鍵字的底層原理)

    線程中并發(fā)安全問題(Sychronized關鍵字的底層原理)

    Sychronized的底層原理 ? sychronized 對象鎖采用互斥方式讓同一時刻至多只有一個線程能持有對象鎖,其他線程想獲取這個對象鎖只能被阻塞。 Monitor Sychronized的底層實現(xiàn)Monitor。 WaitSet:關聯(lián)調(diào)用了wait方法的線程,用于存儲處于等待狀態(tài)的線程。 EntryList:關聯(lián)了沒有獲得

    2024年02月16日
    瀏覽(22)
  • 【C++】多態(tài) ④ ( 多態(tài)實現(xiàn)原理 | C++ 聯(lián)編概念 | 鏈接屬性 | 內(nèi)部鏈接 | 外部鏈接 | 聯(lián)編與鏈接 | 靜態(tài)聯(lián)編 | 動態(tài)聯(lián)編 | 聯(lián)編 與 virtual 關鍵字 )

    【C++】多態(tài) ④ ( 多態(tài)實現(xiàn)原理 | C++ 聯(lián)編概念 | 鏈接屬性 | 內(nèi)部鏈接 | 外部鏈接 | 聯(lián)編與鏈接 | 靜態(tài)聯(lián)編 | 動態(tài)聯(lián)編 | 聯(lián)編 與 virtual 關鍵字 )

    \\\" 聯(lián)編 \\\" Linkage 指的是 將 程序模塊 和 代碼 互相關聯(lián)的過程 , 將不同源文件中的 同名函數(shù) 或 變量 進行鏈接 ; 在 C++ 語言中 , 每個 函數(shù) 或 變量 都有一個 鏈接屬性 , 該鏈接屬性決定了該 函數(shù) 或 變量 是否可以在其他源文件中使用 ; 聯(lián)編 是通過 聲明函數(shù)或變量 的 鏈接屬性

    2024年02月05日
    瀏覽(19)
  • 【C++】C 語言 和 C++ 語言中 const 關鍵字分析 ( const 關鍵字左數(shù)右指原則 | C 語言中常量的原理和缺陷 | C++ 語言中常量原理 - 符號表存儲常量 )

    【C++】C 語言 和 C++ 語言中 const 關鍵字分析 ( const 關鍵字左數(shù)右指原則 | C 語言中常量的原理和缺陷 | C++ 語言中常量原理 - 符號表存儲常量 )

    【C 語言】const 用法 ( 常量指針 - const 在 * 左邊 - 修飾數(shù)據(jù)類型 - 內(nèi)存不變 | 指針常量 - const 在 * 右邊 - 修飾變量 - 指針不變 ) 普通類型數(shù)據(jù)的常量定義時 , const 在 數(shù)據(jù)類型 的 左邊 和 右邊 其作用 是相同的 ; 指針數(shù)據(jù)的相關常量類型 : const 在 指針符號

    2024年02月11日
    瀏覽(24)
  • 用python實現(xiàn)給出關鍵字查找并標注pdf文件中關鍵字

    要在Python中標注PDF文件中的,可以使用Python的PDFMiner庫和Python的matplotlib庫。 首先,需要安裝這兩個庫??梢允褂胮ip命令進行安裝: shell 復制代碼 pip install pdfminer.six matplotlib 接下來,可以使用以下代碼實現(xiàn)查找和標注功能: python 復制代碼 import pdfminer ? from pdf

    2024年01月16日
    瀏覽(89)
  • React實現(xiàn)關鍵字高亮

    React實現(xiàn)關鍵字高亮

    先看效果: 實現(xiàn)很簡單通過以下這個函數(shù): 展示某段文本時調(diào)用該函數(shù)處理后,在展示就能實現(xiàn)高亮效果 原理是: 這個函數(shù)的作用是在給定的文本中,將指定的進行高亮標記。它接受兩個參數(shù):text(要處理的文本)和 keyword(要高亮標記的)。 函數(shù)首先使用

    2024年02月13日
    瀏覽(93)
  • vue實現(xiàn)搜索高亮關鍵字

    模仿瀏覽器中ctrl+f實現(xiàn)搜索 高亮顯示 思路: 通過ref獲取dom元素 刪除當前高亮色; 設置本次搜索的高亮; 進行內(nèi)容替換; 為首個進行高亮,設置為當前; 關鍵代碼: 定義一個正則 key就代表要高亮的字符串,i 代表匹配大小寫 g代表全局匹

    2024年02月10日
    瀏覽(23)
  • JavaFx 關鍵字高亮文本實現(xiàn)

    JavaFx 關鍵字高亮文本實現(xiàn)

    原文地址:JavaFx 高亮文本實現(xiàn) - Stars-One的雜貨小窩 整藍奏云批量下載器里的搜索功能想到的一個高亮功能,借助textflow組件來實現(xiàn),記錄一下 本文基于TornadoFx框架進行編寫,封裝工具代碼是kotlin版本 然后也是順便把這個封裝成了stars-one/common-controls 里的 xHighLightText

    2024年02月04日
    瀏覽(20)
  • Python批量實現(xiàn)word中查找關鍵字

    Python批量實現(xiàn)word中查找關鍵字

    ?一、背景 ????????在日常辦公和文檔處理中,我們常常需要在大量的Word文檔中查找特定的,然后進行接下來的操作,比如替換等。手動逐個打開并搜索文檔顯然是費時費力的。因此,利用Python編寫一個批量實現(xiàn)Word中查找的程序可以大大提高效率和減

    2024年02月16日
    瀏覽(127)
  • 基于GEWE框架實現(xiàn)微信關鍵字回復

    小提示: 發(fā)送一些特殊的消息類型 注意參數(shù) 請求URL: http://域名地址/api/message/sendapp 請求方式: POST 請求頭: Content-Type:application/json X-GEWE-TOKEN: 后臺獲取 參數(shù): 參數(shù)名稱 數(shù)據(jù)類型 必填 說明 appid string 是 設備id to_wxid string 是 接收人 wxid/chatroomid xml string 是 app消息的xml,截

    2024年02月11日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包