iOS雜湊表快取窺探

weixin_34214500發表於2018-08-20

1.

1317036-8e2c56f4bd69933c.png
1

2. 雜湊表(雜湊表)是以空間換時間.

剛開始為cache_t分配一定的記憶體, 如10, 當記憶體不夠用時, 記憶體擴大2倍, 依次類推

3. 表格大概如下:

1317036-97fef0735d687a2a.png
2
  • 左邊是索引, 右邊是 bucket_t 結構體

  • 如上圖所示, bucket_t包括 _keyIMP, _key 就是SEL

4.iOS arm64 雜湊表儲存原理:

    1. 初始時, 為物件的cach_t分配一個空間, 值為NULL
    1. 呼叫方法時, 為物件傳送一個 SEL 訊息, 如 @selector(personTest), 將這個方法快取
    1. 系統用 SEL_mask 作按位與計算: @selector(personTest) & _mask , 假設其值==2,
    1. 檢查索引2 對應的空間是否為NULL , 如果為NULL 就將這個bucket_t 快取在索引2對應空間
    1. 如果不為空, 索引減1, 再檢查是否為NULL, 依次類推. 如果索引<0, 則使索引 =_mask - 1, 直至找到索引對應空間為NULL, 再快取

5. 對應的查詢步驟:

    1. 呼叫方法時, 為物件傳送一個 SEL 訊息, 如 @selector(personTest)
    1. 系統用SEL_mask 作按位與計算: @selector(personTest) & _mask , 假設其值==2,
    1. 得到索引2 的bucket_t , 判斷其中的 SEL 是否與傳過來的 SEL 相同, 如果相同, 這個_imp就是尋找的方法
    1. 如果不相同, 索引減1, 再比較SEL, 依次類推. 如果索引<0, 則使索引 = _mask - 1, 直至找到_imp

6. 為什麼按位&_mask?

按位與 可保證得到的值 <= _mask, 這樣就不會超出分配的空間.

注: 有的系統是求餘 %, 如java, 這樣也能保證 <= _mask

7. 為什麼有 -1 的演算法, 也是因為按位與, 因為不同的值 & _mask, 可能結果相同. 如果已經被佔了, 就-1:

1317036-6f5c5326afb83d61.png
3

8. 如果空間超出原來的_mask, 則 _mask *= 2.

每一次_mask 擴容, 雜湊表清空, 只留下一個方法佔用, 是導致它擴容的方法.

    1. 原始碼:
1317036-7d8dc75a70af448a.png
4
    1. 例項:
1317036-853d824815728c48.png
5

9.列印雜湊表:

1317036-ac0815af30543b86.png
9.1
1317036-c1ed92ec7eedff1c.png
9.2
    1. 可看到有的空間為NULL

10. 測試 & _mask 得到方法:

1317036-e05b6e3921481fc4.png
10.1
列印:
1317036-4c38231375e37dbe.png
10.2

注: selector 轉化成數字型別才能 & , 所以強轉成 long long.

11. 將地址 轉化 成方法名:

1317036-da792134e68e2463.png
11

相關文章