02.Retain&Release
前言
到现在我们接触到了三种指针: TaggedPointer 、 Nonpointer isa 和 纯isa 。
经过上文对 TaggedPointer 的探索,我们接触到了 Reatin 和 Release ,发现他们对 TaggedPointer 有特殊处理的。本文将更加深入的对 Reatin 和 Release 进行研究。
一、 Retain
objc_object::rootRetain(bool tryRetain, objc_object::RRVariant variant)
{
// 不处理 TaggedPointer 直接 return
if (slowpath(isTaggedPointer())) return (id)this;
...
do {
transcribeToSideTable = false;
newisa = oldisa;
if (slowpath(!newisa.nonpointer)) {
// 非 nonpointer 通过 sidetable 处理
ClearExclusive(&isa.bits);
if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
else return sidetable_retain(sideTableLocked);
}
...
uintptr_t carry; // 标志 extra_rc 容量是否还能够承受
newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry); // extra_rc++
if (slowpath(carry)) {
// 超出 extra_rc 容量
// newisa.extra_rc++ overflowed
if (variant != RRVariant::Full) {
ClearExclusive(&isa.bits);
return rootRetain_overflow(tryRetain);
}
// 保留一般的引用计数,并将另一半拷贝到 side table
// Leave half of the retain counts inline and
// prepare to copy the other half to the side table.
if (!tryRetain && !sideTableLocked) sidetable_lock();
sideTableLocked = true;
transcribeToSideTable = true;
newisa.extra_rc = RC_HALF;
newisa.has_sidetable_rc = true;
}
} while (slowpath(!StoreExclusive(&isa.bits, &oldisa.bits, newisa.bits)));
if (variant == RRVariant::Full) {
if (slowpath(transcribeToSideTable)) {
// Copy the other half of the retain counts to the side table.
sidetable_addExtraRC_nolock(RC_HALF);
}
if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
} else {
ASSERT(!transcribeToSideTable);
ASSERT(!sideTableLocked);
}
return (id)this;
}小结
TaggedPointer不处理,直接 returnNonpointer isaBITFIELD和SideTable结合使用当
BITFIELD的extra_rc容量足够的时候持续 ++当
BITFIELD的extra_rc容量不够的时候extra_rc减半,拷贝一半到SideTable进行管理同时标志位
has_sidetable_rc改变
纯isa通过
SideTable管理
二、 Release
小结
TaggedPointer不处理,直接 returnNonpointer isaBITFIELD和SideTable结合使用当
BITFIELD的extra_rc容量未见底的时候持续 --当
BITFIELD的extra_rc容量见底的时候检查标志位
has_sidetable_rc使用了
SideTable将
SideTable中的引用计数转移回BITFIELD的extra_rc进行处理
未使用
SideTable需要销毁
纯isa通过
SideTable管理
三、 总结
通过对 Retain 和 Release 源码的探索,发现使用 TaggedPointer 和 Nonpointer isa 在内存管理的效率上会更高。一旦 SideTable 介入,流程就回变的复杂还要上锁解锁,影响效率。虽然一般开发过程中很难遇到这种情况,但是理解了这些后,对一些问题一些现象就能更清楚的看到本质。
参考
Last updated
Was this helpful?