一、引用計(jì)數(shù)值存儲(chǔ)位置
OC對(duì)象的引用計(jì)數(shù)值存儲(chǔ)在對(duì)象的isa指針中,isa的結(jié)構(gòu)如下:
isa結(jié)構(gòu)體:
union isa_t
{
struct {
...
uintprt_t has_sidetable_rc; // 引用計(jì)數(shù)是否存在sidetable中
uintprt_t extra_rc ; // 存儲(chǔ)的值為引用計(jì)數(shù)值-1
}
}
如果has_sidetable_rc==0,引用計(jì)數(shù)值就存儲(chǔ)在extra_rc中;如果has_sidetable_rc ==1,表示計(jì)數(shù)值超出了extra_rc 的存儲(chǔ)范圍(19個(gè)字節(jié)),此時(shí)計(jì)數(shù)值存儲(chǔ)在sidetable中。
sideTable結(jié)構(gòu):
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
}
sideTable的refcnts存儲(chǔ)著引用計(jì)數(shù),refcnts是個(gè)散列表,存儲(chǔ)數(shù)據(jù)是以對(duì)象地址為key,引用計(jì)數(shù)值為value存儲(chǔ)。sideTable是靜態(tài)數(shù)據(jù),獲取某個(gè)對(duì)象引用計(jì)數(shù)值時(shí),通過(guò)對(duì)象地址,在靜態(tài)的sideTable表中進(jìn)行查找。
二、如何做到自動(dòng)釋放的
- 工程的main入口有一個(gè)autoReleasePool,每個(gè)線程內(nèi)部也自帶了autoReleasePool。主線程的runloop循環(huán)時(shí)會(huì)創(chuàng)建一個(gè)autoreleasePool,結(jié)束時(shí)會(huì)會(huì)觸發(fā)pool里的內(nèi)存釋放邏輯,處理完成后銷毀該autoreleasePool,下個(gè)循環(huán)開(kāi)始時(shí)會(huì)創(chuàng)建新的pool。子線程不會(huì)一直創(chuàng)建、銷毀pool。
- arc下的對(duì)象初始化后,編譯器會(huì)自動(dòng)往后面追加autorelease標(biāo)識(shí),程序運(yùn)行時(shí)就會(huì)把這個(gè)對(duì)象存儲(chǔ)在最近的autoReleasePool中。autoReleasePool要傾倒時(shí),會(huì)檢測(cè)里面的對(duì)象是否有引用計(jì)數(shù)為0的,有則觸發(fā)改對(duì)象的dealloc邏輯
三、Dealloc
引用計(jì)數(shù)為0時(shí),會(huì)觸發(fā)dealloc方法,dealloc過(guò)程是先子類->父類...->NSObject。
dealloc做的工作包括:
1. C++函數(shù)釋放: objc_cxxDestruct
2. 移除關(guān)聯(lián)屬性:_object_remove_assocations
3. 將弱引用自動(dòng)設(shè)置nil: weak_clear_no_lock(&table.weak_table,(id)this)
4. 引用計(jì)數(shù)處理:table.refcnts.erase(this)
5. 銷毀對(duì)象:free(obj)