iOS 底层 - 内存管理之引用计数存储

2020-04-17  本文已影响0人  水中的蓝天

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢 !

写在前面:

自从64位操作系统以后,引用计数被直接存储在优化过的ISA(共用体)指针的extra_rc中,extra_rc拥有19位的内存来存储引用计数减一,
随着持有者的增多引用计数也随之增大,当引用计数值过大,extra_rc中无法存储时,就会把引用计数存储到一个SideTable类的refcnts属性中;

图解:

引用计数存储.png

SideTable本质上是一个结构体,如下图:

struct SideTable {
    spinlock_t slock;             
    RefcountMap refcnts;     
    weak_table_t weak_table;
}

这一顿操作猛如虎,我咋还晕着呢 ?SideTable到底是个啥 ?

不要慌!不要慌!不要慌!😁😁😁😁😁😁😁

获取一个OC对象的引用计数方法是什么 ?

MRC环境下直接调用对象的retaionCount方法获取

此方法在调试内存管理问题时没有价值。
因为许多框架对象可能保留了一个对象来保存对它的引用,而同时autorelease池可能保存了一个对象上的任意数量的延迟发布,
所以您不太可能从这个方法中获得有用的信息。
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;

注意:只有在对象没有被添加在自动缓存池且没有被其他框架引用的情况下,返回的值才绝对有效

ARC环境使用CoreFoundation中CFGetRetainCount()获取

此函数可能有助于调试内存泄漏,返回核心基础对象的引用计数
CFIndex CFGetRetainCount(CFTypeRef cf);

有存储肯定也有擦除

擦除的具体实现在runtime底层源码的NSObject.mm文件的:void objc_object::clearDeallocating_slow()

需要了解全部过程请移步iOS 底层 - 内存管理之weak指针


NEVER_INLINE void
objc_object::clearDeallocating_slow()
{
    ASSERT(isa.nonpointer  &&  (isa.weakly_referenced || isa.has_sidetable_rc));

    //获取当前obj对应的SideTable
    SideTable& table = SideTables()[this];
    //加锁
    table.lock();
    
    //有weak指针指向
    if (isa.weakly_referenced) {
        //传入弱引用表和当前对象,清空
        weak_clear_no_lock(&table.weak_table, (id)this);
    }
    
    //引用计数存储在sidetable中
    if (isa.has_sidetable_rc) {
        //传入当前对象,擦除存储
        table.refcnts.erase(this);
    }
    //解锁
    table.unlock();
}

用lldb打印一个对象的引用计数

NSObject *obj = [[NSObject alloc] init];

在obj实例化后打断点,并在lldb中输出isa来验证:

(lldb) p obj
(NSObject *) 0 = 0x000000010064b810 //读取obj对象的内存,第一个为成员isa (lldb) x/4gx0
0x10064b810: 0x001d800100350141 0x0000000000000000
0x10064b820: 0x64696c53534e5b2d 0x206b636172547265
//打印isa的值
(lldb) p 0x001d800100350141
(long) 1 = 8303516111405377 //这里需要声明成isa_t的结构才能输出 (lldb) p (isa_t)1
(isa_t) $2 = {
cls = NSObject
bits = 8303516111405377
= {
nonpointer = 1
has_assoc = 0
has_cxx_dtor = 0
shiftcls = 537305128
magic = 59
weakly_referenced = 0
deallocating = 0
has_sidetable_rc = 0
extra_rc = 0
}
}
(lldb)

上一篇下一篇

猜你喜欢

热点阅读