內(nèi)存管理

1. 內(nèi)存布局

  • 保留區(qū) --> 內(nèi)核去 (低~高)
  • 代碼段 --> 已初始化數(shù)據(jù)(.data)--> 未初始化數(shù)據(jù)(.bss)(低~高)
  • 堆(由低到高) --> 棧(由高到低)(低~高)
  • stack:方法調(diào)用
  • heap:通過alloc等分配的對象
  • bss:未初始化的全局變量
  • data:已初始化的全局變量
  • text:代碼段

2. 內(nèi)存管理方案

  • TaggedPointer
  • NONOPOINTER_ISA(64位架構(gòu)下)
  • 散列表(SideTable)
  1. NONPOINTER_ISA(64位)
  • [0] indexed: 標志位 0 代表純指針, 1 代表指針中包含其他內(nèi)容
  • [1] has_assoc: 是否有關(guān)聯(lián)對象
  • [2] has_cxx_dior: 當前對象是都有 c++ 的相關(guān)內(nèi)容
  • [3 ~ 35] shiftcls: 共33位,表示當前對象類對象的指針地址
  • [36 ~ 41] magic: 不涉及
  • [42] weakly_referenced: 是否有弱引用
  • [43] deallocating: 是否正在進行 dealloc 操作
  • [44] has_sidetable_rc:是否有額外使用SideTable 計算引用計數(shù)內(nèi)容
  • [45 ~ 63]extra_rc 在指針中記錄引用計數(shù)
  1. SideTables() 結(jié)構(gòu)
  • 哈希表(快速定位)
  • spinlock_t (自旋鎖,分離鎖)
  • 引用計數(shù)表
  • 弱引用表
  1. Spinlock_t
  • Spinlock_t 是 “忙等” 的鎖。
  • 適用于輕量訪問
  1. RefcountMap(引用計數(shù)表)
  • 通過“指針” ptr 通過哈希查找,找到對象的引用計數(shù)
  1. weak_table_t (弱引用計數(shù)表)
  • 哈希表

3. 引用計數(shù)管理

  • alloc
    調(diào)用C函數(shù) calloc

  • retain

    1. 獲取到當前對象的 SideTable
    2. SideTable 獲取當前對象的引用計數(shù)值
    3. 引用計數(shù)值 + 1
  • release

    1. 獲取到當前對象的 SideTable
    2. SideTable 獲取當前對象的引用計數(shù)值
    3. 引用計數(shù)值 - 1
  • retainCount

    1. 獲取到當前對象的 SideTable
    2. SideTable 獲取當前對象的引用計數(shù)值
    3. 引用計數(shù)值 + 1
  • dealloc
    當前對象是否可以直接釋放一句以下判斷條件
    nonpointer_isa
    weakly_referenced
    has_assoc 是否有關(guān)聯(lián)對象
    has_cxx_dtor 是否有C++內(nèi)容,或是否使用arc管理內(nèi)存
    has_sidetable_rc 當前對象的引用計數(shù)是否通過sidetable表維護的
    以上全部為否才可以調(diào)用C函數(shù)直接釋放
    否則就要調(diào)用object_dispose() 進行釋放

  • object_dispose
    開始
    objc_destructInstance(): c++釋放、移除關(guān)聯(lián)對象、將弱引用指針置位nil、清除引用計數(shù)
    c函數(shù)free()
    結(jié)束

4. 弱引用管理

添加弱引用變量的流程
objc_initWeak()
storeWeak()
weak_register_no_lock()
1 通過對象指針hash計算查找
2 如果已經(jīng)存在了弱引用數(shù)組,則添加
3 如果沒有,則創(chuàng)建弱引用數(shù)組
清除weak變量,同事設(shè)置為nil

5. 自動釋放池

  • runloop將要結(jié)束時調(diào)用pop操作
  • 多層嵌套就是多次插入哨兵對象
  • 在for循環(huán)中alloc創(chuàng)建了較大的內(nèi)存消耗是,可手動插入autoReleasePool來釋放內(nèi)存對象

6. 循環(huán)引用

自循環(huán)引用
相互循環(huán)應用
多循環(huán)引用
如何破除

避免產(chǎn)生
在合適的時機手動破除循環(huán)引用
__weak
__block(ARC下會被強引用)
__unsafe_unretained 修飾對象不會增加引用計數(shù),但是會產(chǎn)生懸垂指針

解決NSTimer的循環(huán)引用問題
NSTimer會被Runloop引用,所以必須手動釋放NSTimer來解除引用。
采用中間對象,同時弱引用NSTimer和對象,當對象被釋放后,NSTimer回調(diào)后,判斷弱引用對象已經(jīng)釋放為nil,此時則invalidate timer,將NSTimer置位nil,此時NSTimer也被成功釋放。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 數(shù)據(jù)結(jié)構(gòu) *Spinlock_t*RefcountMap*weak_table_t Spinlock_t: *Sp...
    BabyNeedCare閱讀 765評論 1 2
  • 1、內(nèi)存布局 stack:方法調(diào)用 heap:通過alloc等分配對象 bss:未初始化的全局變量等。 data:...
    AKyS佐毅閱讀 1,712評論 0 19
  • 內(nèi)存布局 ① 棧區(qū)stack:方法調(diào)用會在棧區(qū)展開;② 堆區(qū)heap:通過alloc分配的對象,copy后的blo...
    小王的知識屋閱讀 394評論 0 0
  • 內(nèi)存布局 stack區(qū):方法調(diào)用 heap區(qū) (堆區(qū)):alloc分配的一些對象 bss :未初始化的全局變量 d...
    叔簡閱讀 582評論 0 1
  • 在開發(fā)中,內(nèi)存管理是一個必要的技能,研究iOS 開發(fā),我們通過內(nèi)存布局、內(nèi)存管理方案、數(shù)據(jù)結(jié)構(gòu)、ARC/MRC、引...
    大馮宇宙閱讀 812評論 0 3

友情鏈接更多精彩內(nèi)容