引入計數儲存在SideTables表中儲存結構如圖所示。
1.Retain實現原理。
1.1對物件retain之後實現過程。
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];//從SideTables中取出SideTable。
table.lock();
size_t& refcntStorage = table.refcnts[this];//根據this地址取出refcntStorage
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {//如果沒有超出引用計數最大值
refcntStorage += SIDE_TABLE_RC_ONE;//引用計數加4也就是向左移動兩位。
}
table.unlock();
return (id)this;
}
複製程式碼
1.2引用計數值獲取。
objc_object::sidetable_retainCount()
{
SideTable& table = SideTables()[this];
size_t refcnt_result = 1;
//物件初始化時預設為1之後每次對物件retain引入計數值加1
table.lock();
RefcountMap::iterator it = table.refcnts.find(this);//獲取RefcountMap
if (it != table.refcnts.end()) {//能找到this物件
// this is valid for SIDE_TABLE_RC_PINNED too
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT;//
//it->second是獲取到it的value
//>> SIDE_TABLE_RC_SHIFT上邊獲取的value向左移動兩位獲取到引用計數器的值。
}
table.unlock();
return refcnt_result;//返回引用計數值
}
複製程式碼
2.Release實現原理
objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
assert(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];//獲取到SideTable
bool do_dealloc = false;//是否要被dealloc
table.lock();//鎖住table表
RefcountMap::iterator it = table.refcnts.find(this);//獲取到RefcountMap
if (it == table.refcnts.end()) {//沒有找到this
do_dealloc = true;
table.refcnts[this] = SIDE_TABLE_DEALLOCATING;//設定為需要dealloc
} else if (it->second < SIDE_TABLE_DEALLOCATING) {//沒有引用計數值
// SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;//給it->second賦值
} else if (! (it->second & SIDE_TABLE_RC_PINNED)) {//引用計數減一
it->second -= SIDE_TABLE_RC_ONE;
}
table.unlock();
if (do_dealloc && performDealloc) {//物件需要被銷燬
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);//傳送訊息呼叫dealloc銷燬物件。
}
return do_dealloc;
}
複製程式碼
2.1通過this沒有找到RefcountMap
如果沒找打RefcountMap物件do_dealloc 設定位 true table.refcnts[this] = SIDE_TABLE_DEALLOCATING設定標誌位為1為下邊清除weak——table——t表中的物件設定為nil做準備。 ##2.2引入計數已經清0
do_dealloc = true;
it->second |= SIDE_TABLE_DEALLOCATING;
複製程式碼
程式碼和2.1操作相同標誌位設定。
2.3引用計數減1。
it->second -= SIDE_TABLE_RC_ONE;
複製程式碼
2.4根據標誌位判斷是否需要dealloc。
if (do_dealloc && performDealloc) {//物件需要被銷燬
((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);//傳送訊息呼叫dealloc銷燬物件。
}
複製程式碼
如果標誌位都為YES呼叫objc_msgSend銷燬物件。
3.refcntStorage結構事例
SIDE_TABLE_WEAKLY_REFERENCED (1UL<<0)
SIDE_TABLE_WEAKLY_REFERENCED(是否有弱引用)1,有0,沒有
複製程式碼
SIDE_TABLE_DEALLOCATING (1UL<<1)
SIDE_TABLE_DEALLOCATING(是否要被銷燬)1,被標記 0,不需要被銷燬
複製程式碼
SIDE_TABLE_RC_ONE (1UL<<2)
SIDE_TABLE_RC_ONE新增引用計數的值左移兩位想當於加4.
複製程式碼
SIDE_TABLE_RC_PINNED (1UL<<(WORD_BITS-1))
SIDE_TABLE_RC_PINNE(如果為1引用計數到達最大值)
複製程式碼
#ifdef __LP64__
# define WORD_SHIFT 3UL
# define WORD_MASK 7UL
# define WORD_BITS 64//64位系統定義為64
#else
# define WORD_SHIFT 2UL
# define WORD_MASK 3UL
# define WORD_BITS 32
#endif
複製程式碼