在 属性的setter和getter方法 中,我们可以发现, objc_retain
方法被调用.
那么对象的引用计数管理,是怎么进行的呢?
- (void)testWeak{
NSObject *objct = [[NSObject alloc] init];
NSObject *o2 = objct;
o2 = nil;
}
arm64 汇编
"-[A testWeak]": ; @"\01-[A testWeak]"
sub sp, sp, #80 ; =80 ; sp = sp - 80
stp x29, x30, [sp, #64] ; 16-byte Folded Spill 将 x29 和 x30 的值存储到 sp+64
add x29, sp, #64 ; =64 x29 = sp+64
stur x0, [x29, #-8] ; sp + 56 = x0 = self
stur x1, [x29, #-16] sp + 48 = x1 = SEL
adrp x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGE ; 加载 类对象列表 base地址,存储到x8
add x8, x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGEOFF ; 根据偏移量计算 NSObject 的类对象地址, 地址 x8 = x8 + 偏移地址
ldr x0, [x8] ; x0 = x8;
bl _objc_alloc ; 调用 id _Nullable objc_alloc(Class _Nullable cls) 方法
adrp x8, _OBJC_SELECTOR_REFERENCES_@PAGE; 加载方法列表 base地址,存储到x8
add x8, x8, _OBJC_SELECTOR_REFERENCES_@PAGEOFF ; 根据偏移量计算 NSObject 的 -(instancetype)init 方法地址, 地址 x8 = x8 + 偏移地址
ldr x1, [x8] ; -(instancetype)init 方法放到x1
bl _objc_msgSend ; 调用init方法,
sub x8, x29, #24 ; =24; x8 = sp+40;
stur x0, [x29, #-24] ; x0 存储到 sp+40 = object,对应了 NSObject *objct = [[NSObject alloc] init]; 代码
ldur x0, [x29, #-24] ; sp+40存储到x0 = object
str x8, [sp, #24] ; 8-byte Folded Spill , x8 放到 sp + 24 = object
bl _objc_retain ; 调用 _objc_retain 方法, 类似 [objct retain]; 此时引用计数器的值为 2
add x8, sp, #32 ; =32 x8 = sp+32
str x0, [sp, #32] ; x0 放到 sp + 32 = object 对应NSObject *o2 = objct; 代码
mov x0, x8 ; x0 = x8 = sp+32 = o2;
mov x9, #0; x9 = 0
mov x1, x9; x1 = 0;
str x8, [sp, #16] ; 8-byte Folded Spill ; sp+16 = x0 = o2
str x9, [sp, #8] ; 8-byte Folded Spill sp+8 = x9 = 0;
bl _objc_storeStrong ; 调用 void objc_storeStrong(id *location, id obj)方法 对应了o2 = nil; 方法
ldr x0, [sp, #16] ; 8-byte Folded Reload x0 = sp + 16; = o2
ldr x1, [sp, #8] ; 8-byte Folded Reload x1 = sp+8 = 0; 释放 o2
bl _objc_storeStrong ; 作用域结束, object = nil
ldr x0, [sp, #24] ; 8-byte Folded Reload x0 = sp + 24 = object;
ldr x1, [sp, #8] ; 8-byte Folded Reload x1 = sp + 8 = 0;
bl _objc_storeStrong ; 释放对象
ldp x29, x30, [sp, #64] ; 16-byte Folded Reload
add sp, sp, #80 ; =80
ret
可以看到
NSObject对象的创建调用了 objc_alloc
函数
关于对象的内存分配和类的关联可以看下面的文章
https://www.jianshu.com/p/532ddbf803a2
引用计数的管理,主要体现在objc_retain``objc_storeStrong
方法中,
可能会想, 对象刚创建出来,引用计数为1, 那么怎么赋值的呢, 但其实是因为引用计数器存储的值是引用计数器减1
在目前最新的源码,
818.2
中,创建对象后引用计数会赋值为1,引用计数器存储的值直接就是引用计数了
objc_retain 和 retain
objc_retain
id objc_retain(id obj)
{
if (!obj) return obj;
if (obj->isTaggedPointer()) return obj;
return obj->retain();
}
id objc_object::retain()
{
ASSERT(!isTaggedPointer());
return rootRetain(false, RRVariant::FastOrMsgSend);
}
rootRetain
这个函数来增加引用计数
ALWAYS_INLINE id
objc_object::rootRetain(bool tryRetain, objc_object::RRVariant variant)
{
if (slowpath(isTaggedPointer())) return (id)this;
bool sideTableLocked = false;
bool transcribeToSideTable = false;
isa_t oldisa;
isa_t newisa;
oldisa = LoadExclusive(&isa.bits);
if (variant == RRVariant::FastOrMsgSend) { // 主要检查是否需要调用objc_msgSend
// These checks are only meaningful for objc_retain()
// They are here so that we avoid a re-load of the isa.
if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) { // 如果具有默认的retain/release/autorelease/方法
ClearExclusive(&isa.bits);
if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
return swiftRetain.load(memory_order_relaxed)((id)this);
}
return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(retain));
}
}
if (slowpath(!oldisa.nonpointer)) {
// a Class is a Class forever, so we can perform this check once
// outside of the CAS loop
if (oldisa.getDecodedClass(false)->isMetaClass()) { //检查isa是不是元类对象,
ClearExclusive(&isa.bits);
return (id)this;
}
}
do {
transcribeToSideTable = false;
newisa = oldisa; // 创建一个临时的isa:newisa,操作都是针对临时变量来操作,最后将newisa的bits信息存储到原始的isa中去,有个do-while去处理存储的逻辑,失败的话就重试
if (slowpath(!newisa.nonpointer)) { // 不是优化过的指针,直接使用sidetable存储计数
ClearExclusive(&isa.bits);
if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
else return sidetable_retain(sideTableLocked);
}
// don't check newisa.fast_rr; we already called any RR overrides
if (slowpath(newisa.isDeallocating())) { // 如果当前正在释放
ClearExclusive(&isa.bits);
if (sideTableLocked) {
ASSERT(variant == RRVariant::Full);
sidetable_unlock();
}
if (slowpath(tryRetain)) { // 直接返回 不增加引用计数
return nil;
} else {
return (id)this;
}
}
uintptr_t carry;
newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry); // extra_rc++ 增加引用计数, carry表示数值是否溢出
if (slowpath(carry)) {
// newisa.extra_rc++ overflowed
if (variant != RRVariant::Full) { // 如果溢出,且当前不是溢出状态,就设置为溢出状态,并且重新调用方法
ClearExclusive(&isa.bits);
return rootRetain_overflow(tryRetain);
}
// 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; // 有引用计数在sidetable里存储
}
} while (slowpath(!StoreExclusive(&isa.bits, &oldisa.bits, newisa.bits)));
if (variant == RRVariant::Full) { // 如果是满的,且 transcribeToSideTable == true
if (slowpath(transcribeToSideTable)) {
// Copy the other half of the retain counts to the side table.
sidetable_addExtraRC_nolock(RC_HALF); // 存储到sidetable
}
if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
} else {
ASSERT(!transcribeToSideTable);
ASSERT(!sideTableLocked);
}
return (id)this;
}
sidetable_addExtraRC_nolock
bool objc_object::sidetable_addExtraRC_nolock(size_t delta_rc)
{
ASSERT(isa.nonpointer);
SideTable& table = SideTables()[this];
// 获取当前的引用计数
size_t& refcntStorage = table.refcnts[this];
size_t oldRefcnt = refcntStorage;
// isa-side bits should not be set here
ASSERT((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0); // 正在释放
ASSERT((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0); // 弱引用正在释放
// 系统计数极限了,直接true
if (oldRefcnt & SIDE_TABLE_RC_PINNED) return true;
uintptr_t carry;
// 增加引用计数
size_t newRefcnt =
addc(oldRefcnt, delta_rc << SIDE_TABLE_RC_SHIFT, 0, &carry);
if (carry) {
// 如果借位保存在这里还溢出,就当做SIDE_TABLE_RC_PINNED次数(32或64最大位数-1的数值)
refcntStorage =
SIDE_TABLE_RC_PINNED | (oldRefcnt & SIDE_TABLE_FLAG_MASK);
return true;
}
else {
refcntStorage = newRefcnt;
return false;
}
}
直接通过 sidetable_retain
增加引用计数
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA // 是否支持优化过的isa指针
ASSERT(!isa.nonpointer);
#endif
SideTable& table = SideTables()[this];
table.lock();
size_t& refcntStorage = table.refcnts[this];
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
refcntStorage += SIDE_TABLE_RC_ONE; // // 引用计数加1,(偏移2位,SIDE_TABLE_RC_ONE = 1<<2)
}
table.unlock();
return (id)this;
}
retain
当我们在MRC手动调用 retain 方法时
- (id)retain {
return _objc_rootRetain(self);
}
id _objc_rootRetain(id obj)
{
ASSERT(obj);
return obj->rootRetain();
}
ALWAYS_INLINE id objc_object::rootRetain()
{
return rootRetain(false, false);
}
最后也调用到rootRetain
获取对象的引用计数
- (NSUInteger)retainCount {
return _objc_rootRetainCount(self);
}
_objc_rootRetainCount(id obj)
{
ASSERT(obj);
return obj->rootRetainCount();
}
rootRetainCount
inline uintptr_t objc_object::rootRetainCount()
{
//TaggedPointer指针 直接返回
if (isTaggedPointer()) return (uintptr_t)this;
sidetable_lock();
isa_t bits = __c11_atomic_load((_Atomic uintptr_t *)&isa.bits, __ATOMIC_RELAXED);
//优化过的 isa 指针
if (bits.nonpointer) {
uintptr_t rc = bits.extra_rc; // extra_rc存储的计数数量
if (bits.has_sidetable_rc) { //bits.has_sidetable_rc标志位为1 表明有存放在sidetable中的引用计数
//读取table的值 相加
rc += sidetable_getExtraRC_nolock();
}
sidetable_unlock();
return rc;
}
sidetable_unlock();
//如果没采用优化的isa指针,则直接返回sidetable中的值
return sidetable_retainCount();
}
retainCount = isa.extra_rc + sidetable_getExtraRC_nolock,即引用计数=isa指针中存储的引用计数+sidetable中存储的引用计数
size_t objc_object::sidetable_getExtraRC_nolock()
{
ASSERT(isa.nonpointer);
//key是 this,存储了对象的table
SideTable& table = SideTables()[this];
//找到 it 否则返回0
// 这里返回的it是RefcountMap类型 it == table.refcnts.end()
// 表示在sidetable中没有找到this对应的引用计数则直接返回0
RefcountMap::iterator it = table.refcnts.find(this);
if (it == table.refcnts.end()) return 0;
// RefcountMap 结构的second值为引用计数值
// DenseMap<DisguisedPtr<objc_object>,size_t,true> RefcountMap;
// it->second 无符号整型,真实的引用计数需要右移2位
else return it->second >> SIDE_TABLE_RC_SHIFT;
}
objc_storeStrong
// location是引用对象的指针的地址,obj是对象本身。
void objc_storeStrong(id *location, id obj)
{
// 取到指针指的旧对象
id prev = *location;
if (obj == prev) {
return;
}
objc_retain(obj); // 新对象计数+1
*location = obj;
objc_release(prev); // 旧对象计数-1
}
objc_release
void objc_release(id obj)
{
if (obj->isTaggedPointerOrNil()) return;
return obj->release();
}
inline void
objc_object::release()
{
ASSERT(!isTaggedPointer());
rootRelease(true, RRVariant::FastOrMsgSend);
}
rootRelease
ALWAYS_INLINE bool
objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)
{
if (slowpath(isTaggedPointer())) return false;
bool sideTableLocked = false;
isa_t newisa, oldisa;
// 获取isa
oldisa = LoadExclusive(&isa.bits);
// 是否有自己的 release 方法
if (variant == RRVariant::FastOrMsgSend) {
// These checks are only meaningful for objc_release()
// They are here so that we avoid a re-load of the isa.
if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) {
ClearExclusive(&isa.bits);
if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
swiftRelease.load(memory_order_relaxed)((id)this);
return true;
}
((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(release));
return true;
}
}
// 是否是元类
if (slowpath(!oldisa.nonpointer)) {
// a Class is a Class forever, so we can perform this check once
// outside of the CAS loop
if (oldisa.getDecodedClass(false)->isMetaClass()) {
ClearExclusive(&isa.bits);
return false;
}
}
retry:
do {
// 临时变量
newisa = oldisa;
if (slowpath(!newisa.nonpointer)) {
ClearExclusive(&isa.bits);
// 不是优化过的isa 直接release
return sidetable_release(sideTableLocked, performDealloc);
}
// 正在释放,返回失败
if (slowpath(newisa.isDeallocating())) {
ClearExclusive(&isa.bits);
if (sideTableLocked) {
ASSERT(variant == RRVariant::Full);
sidetable_unlock();
}
return false;
}
// don't check newisa.fast_rr; we already called any RR overrides
uintptr_t carry;
newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry); // extra_rc--
// 不够减,直接去 underflow
if (slowpath(carry)) {
// don't ClearExclusive()
goto underflow;
}
} while (slowpath(!StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits))); // 合并
if (slowpath(newisa.isDeallocating())) // 是否需要释放
goto deallocate;
if (variant == RRVariant::Full) {
if (slowpath(sideTableLocked)) sidetable_unlock();
} else {
ASSERT(!sideTableLocked);
}
return false;
underflow:
// newisa.extra_rc-- underflowed: borrow from side table or deallocate
// abandon newisa to undo the decrement
newisa = oldisa;
if (slowpath(newisa.has_sidetable_rc)) { // sidetable 是否存有引用计数
if (variant != RRVariant::Full) {
ClearExclusive(&isa.bits);
return rootRelease_underflow(performDealloc); // 再次调用自己,只不过第二个参数是full
}
// Transfer retain count from side table to inline storage.
if (!sideTableLocked) {
ClearExclusive(&isa.bits);
sidetable_lock();
sideTableLocked = true;
// Need to start over to avoid a race against
// the nonpointer -> raw pointer transition.
oldisa = LoadExclusive(&isa.bits);
goto retry; // 重新去减少引用计数
}
// 从sidetable分出来一部分引用计数
// Try to remove some retain counts from the side table.
auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
// 是不是空的表
bool emptySideTable = borrow.remaining == 0; // we'll clear the side table if no refcounts remain there
if (borrow.borrowed > 0) {
// Side table retain count decreased.
// Try to add them to the inline count.
bool didTransitionToDeallocating = false;
// 增加 extra_rc 的值 ,但是要减去1.就不用再去减了
newisa.extra_rc = borrow.borrowed - 1; // redo the original decrement too
newisa.has_sidetable_rc = !emptySideTable;
bool stored = StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits); // 合并
if (!stored && oldisa.nonpointer) { // 合并失败,立刻重试
uintptr_t overflow;
newisa.bits =
addc(oldisa.bits, RC_ONE * (borrow.borrowed-1), 0, &overflow);
newisa.has_sidetable_rc = !emptySideTable;
if (!overflow) {
stored = StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits);
if (stored) {
didTransitionToDeallocating = newisa.isDeallocating(); // 是否需要释放
}
}
}
if (!stored) { // 还是合并失败,重新去走 retry 流程
ClearExclusive(&isa.bits);
sidetable_addExtraRC_nolock(borrow.borrowed);
oldisa = LoadExclusive(&isa.bits);
goto retry;
}
// Decrement successful after borrowing from side table.
if (emptySideTable) // 空表,去释放表
sidetable_clearExtraRC_nolock();
if (!didTransitionToDeallocating) { // 不需要释放就返回
if (slowpath(sideTableLocked)) sidetable_unlock();
return false;
}
}
else {
// Side table is empty after all. Fall-through to the dealloc path.
}
}
deallocate:
// 开始释放
ASSERT(newisa.isDeallocating());
ASSERT(isa.isDeallocating());
if (slowpath(sideTableLocked)) sidetable_unlock();
__c11_atomic_thread_fence(__ATOMIC_ACQUIRE);
if (performDealloc) { // 调用dealloc方法
((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
}
return true;
}
sidetable_subExtraRC_nolock
从sidetable分出来一部分引用计数
objc_object::SidetableBorrow objc_object::sidetable_subExtraRC_nolock(size_t delta_rc)
{
ASSERT(isa.nonpointer);
SideTable& table = SideTables()[this];
RefcountMap::iterator it = table.refcnts.find(this);
if (it == table.refcnts.end() || it->second == 0) {
// Side table retain count is zero. Can't borrow.
// Side table 没有引用计数
return { 0, 0 };
}
size_t oldRefcnt = it->second;
// isa-side bits should not be set here
ASSERT((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0);
ASSERT((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0);
// 分出去引用计数 ,返回分出去的引用计数和剩余的引用计数
size_t newRefcnt = oldRefcnt - (delta_rc << SIDE_TABLE_RC_SHIFT);
ASSERT(oldRefcnt > newRefcnt); // shouldn't underflow
it->second = newRefcnt;
return { delta_rc, newRefcnt >> SIDE_TABLE_RC_SHIFT };
}
release
// Replaced by ObjectAlloc
- (oneway void)release {
_objc_rootRelease(self);
}
NEVER_INLINE void _objc_rootRelease(id obj)
{
ASSERT(obj);
obj->rootRelease(); // 也调用到了上面的方法
}
也就是说,在引用计数减少的时候判断是否去释放
hasCustomRR()
// hasCustomRR函数通过掩码计算,检查类(包括其父类)中是否含有默认的方法,并且有则调用默认的方法;如果没有,调用其他方法.
bool hasCustomRR() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
}
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
网友评论