內(nèi)存管理
- 內(nèi)存布局
- 內(nèi)存管理方案
- 數(shù)據(jù)結(jié)構(gòu)
- ARC & MRC
- 引用計數(shù)
- 弱引用
- 自動釋放池
- 循環(huán)引用
1.內(nèi)存布局
- 內(nèi)核區(qū)
- stack棧(向下增長):方法調(diào)用
- heap堆(向上增長):通過alloc等分配的對象
- bss: 未初始化的全局變量、靜態(tài)變量等。
- data:已初始化的全局變量等
- text:程序代碼
2.內(nèi)存管理方案
- TaggedPointer(NSNumber等小對象)
- NONPOINTER_ISA(64位架構(gòu))
- 散列表
- 一個復(fù)雜的數(shù)據(jù)結(jié)構(gòu),其中包含了弱引用表+引用計數(shù)表
2.1 NONPOINTER_ISA
arm64架構(gòu)
- 0:indexed標(biāo)志位
- 為0代表當(dāng)前指針是一個純isa指針,里面內(nèi)容直接代表了當(dāng)前對象的類對象的地址
- 為1代表:除了當(dāng)前對象的類對象的地址,還有一些內(nèi)存管理數(shù)據(jù)(非指針isa)
- 1:has_assoc當(dāng)前對象是否有關(guān)聯(lián)對象 0 沒有 1有
- 2:has_cxx_dtor 當(dāng)前對象是否使用了c++相關(guān)代碼
- 3~35(33位):shiftcls 當(dāng)前對象的類對象的內(nèi)存地址
- 36~41(6位):magic
- 42:weakly_referenced 當(dāng)前對象是否有弱引用指針
- 43:deallocating 當(dāng)前對象是否正在進行dealloc
- 44:has_sidetable_rc 當(dāng)前對象是否在散列表里(當(dāng)前isa指針,所存儲的引用計數(shù)達到上限)
- 45~63:extra_rc 額外引用計數(shù)的存儲
2.2 散列表方式
SideTables()結(jié)構(gòu),哈希表
- 對應(yīng)多個SideTable
- SideTable 包含
- spinlock_t 自旋鎖
- RefcountMap 引用計數(shù)表
- weak_table_t 弱引用表
2.3 分離鎖
- 為啥用多個SideTable? 為了效率
- 分離鎖:可以并發(fā)執(zhí)行引用計數(shù)改變,但是同一個表只能按順序
2.4 怎樣實現(xiàn)管束分流
SideTables本質(zhì)是一張Hash表
3. 數(shù)據(jù)結(jié)構(gòu)
- spinlock_t 自旋鎖
- RefcountMap 引用計數(shù)表
- weak_table_t 弱引用表
3.1 Spinlock_t 自旋鎖
"忙等"鎖
適用于輕量訪問
3.2 RefcountMap 引用計數(shù)表
hash表實現(xiàn), 插入、獲取 通過同一個函數(shù)
size_t
0:weakly_referenced 是否弱引用
1:deallocating 是否正在dealloc
2~63:RC
3.2 weak_table_t 引用計數(shù)表
key --Hash函數(shù)--> Value(weak_entry_t)
4 MRC & ARC
4.1 MRC 手動引用計數(shù)
- alloc
retainreleaseretainCountautorelease- dealloc(MRC要寫super,ARC不寫)
4.2 ARC 自動引用計數(shù)
- ARC是LLVM和Runtime協(xié)作的結(jié)果
- ARC禁止調(diào)用4.1中的標(biāo)紅函數(shù)
- ARC中新增weak、strong
5 引用計數(shù)管理
實現(xiàn)原理分析
- alloc
- retain
- release
- retainCount
- dealloc
5.1 alloc
c函數(shù)calloc,此時并沒有設(shè)置引用計數(shù)為1,但是為啥獲取的retainCount是1要看retainCount的實現(xiàn)
5.2 retain
// 找到對應(yīng)的引用計數(shù)表 hash查找
SideTable& table = SideTables()[this];
// 獲取當(dāng)前引用計數(shù) hash查找
size_t& refcountStroage = table.refcnts[this];
// 自增
refcountStroage += SIDE_TABLE_RC_ONE;
5.3release 實現(xiàn)
// 找到對應(yīng)的引用計數(shù)表 hash查找
SideTable& table = SideTables()[this];
// 獲取當(dāng)前引用計數(shù) hash查找
RefcountMap::iterator it = table.refcnts.find(this);
// 自減
it->second -= SIDE_TABLE_RC_ONE;
5.4retainCount 實現(xiàn)
// 找到對應(yīng)的引用計數(shù)表 hash查找
SideTable& table = SideTables()[this];
size_t refcnt_result = 1;
// 獲取當(dāng)前引用計數(shù) hash查找
RefcountMap::iterator it = table.refcnts.find(this);
// 1+引用計數(shù)右便宜然后
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;
5.5 dealloc 實現(xiàn)
st=>start: 開始
e=>end: 結(jié)束
op=>operation: _objc_rootDealloc()
op0=>operation: rootDealloc()
cond=>condition: 是否可以釋放?
op1=>operation: c函數(shù)free()
op2=>operation: object_dispose()
st->op->op0->cond
cond(yes)->op1->e
cond(no)->op2->e
是否釋放的5個判斷條件
- nonpointer_isa
- weakly_referenced
- has_assoc
- has_cxx_dtor
- has_sidetable_rc