OC内存管理

作者: huoshe2019 | 来源:发表于2019-10-15 15:26 被阅读0次
    内存管理

    一、内存布局

    内存布局 内存1 内存2

    二、内存管理方案

    2.1、方案介绍

    • TaggedPointer
      比如NSNumber类型
    • NONPOINTER_ISA
      针对64位架构
    • 散列表
      包括引用计数表和弱引用计数表

    2.2、散列表

    散列表

    问题1:为什么不是一个SideTable?

    存在效率问题。操作其中一个对象引用计数时,会被加锁,后面对象就会要一直等待。

    为了解决上述问题:引入了分离锁的计数解决方案,提高访问效率。

    分离锁

    问题2:怎样通过一个对象指针快速定位属于哪个Side Tables?

    通过哈希查找、不涉及遍历、查找效率高。
    Side Tables的本质是一张Hash表

    三、数据结构

    3.1、Spinlock_t(自旋锁)

    • Spinlock_t是“忙等”的锁。
    • 适用于轻量访问。

    3.2、引用计数表

    • 是一个哈希表。
    • 通过哈希查找。
    • 通过指针查找引用计数。
    引用计数查找1 引用计数查找2

    3.3、弱引用计数表

    弱引用计数表

    四、MRC和ARC相关

    4.1、MRC(手动引用计数)

    MRC

    其中红色部分不能在MRC下使用!

    4.2、ARC(自动引用计数)

    ARC

    五、引用计数管理

    • alloc
    • retain
    • release
    • retainCount
    • dealloc

    5.1、alloc实现

    经过一系列调用,最终调用了C函数calloc。
    此时并没有设置引用计数为1

    5.2、retain实现

    retain

    5.3、release实现

    release

    5.4、retainCount实现

    retainCount

    这里解答了alloc为什么引用计数没有加1,而retainCount获取的数值却为1。

    5.5、dealloc实现(重点)

    5.5.1、 dealloc实现流程图

    dealloc

    5.5.2、 object_dispose实现

    object_dispose

    5.5.3、 objc_destructInstance实现

    objc_destructInstance

    问题3:通过关联对象为一个类添加实例变量,在对象的dealloc方法中是否有必要对关联对象进行移除?

    没必要,因为系统已经进行移除了(如上图)。

    5.5.4、 clearDeallocating实现

    clearDeallocating

    问题4:为什么一个弱引用对象指针,在对象销毁后,会自动置为nil?

    1、因为在对象销毁后,会调用dealloc方法。
    2、在dealloc内部方法实现中,会调用weak_clear_no_lock()函数。
    3、在该函数内部,会根据当前对象指针,利用哈希算法,查找弱引用表,然后取出弱引用数组,遍历这个数组,将弱引用指针全部置为nil。

    六、弱引用管理

    问题5:一个weak变量是怎样被添加到弱引用计数表中的?

    解释:
    这里讲解一下weak修饰的变量会经历哪些步骤就可以了。
    1、一个被声明为weak的变量,经过编译器编译后,会调用objc_initWeak()storeWeak()weak_register_no_lock()函数。
    2、在weak_register_no_lock()函数中,进行一个弱引用添加。具体添加的位置,是通过哈希算法查找的。

    6.1、系统内部函数调用

    weak编译 objc_initWeak

    weak_register_no_lock()
    通过哈希算法,查找对应位置;将弱引用weak变量添加到弱引用计数表中。

    6.2、清除变量,弱引用指针指向nil

    dealloc内部调用

    这里主要是weak_clear_no_lock起到主要作用。

    七、自动释放池

    问题6:下面的array什么时候释放

    自动释放池

    在当次runloop将要结束的时候,对前一次的AutoreleasePool进行pop操作,同时会push一个新的AutoreleasePool。

    所以,当前的array会在当前runloop将要结束的时候,调用AutoreleasePoolPage::pop,对对象进行释放。

    问题7:AutoreleasePool的实现原理是怎样的?

    是以为节点通过双向链表 的形式组合而成。

    问题8:AutoreleasePool为何可以嵌套使用?

    因为多次嵌套在底层的反应是:多次插入哨兵对象。如果当前AutoreleasePoolPage没有满,当然可以插入对象。

    问题9:什么是自动释放池?

    是以为节点通过双向链表 的形式组合而成。

    问题10:AutoreleasePool使用场景

    在for循环中alloc图片数据等内存消耗大的场景(需要创建很多临时对象),可以手动插入AutoreleasePool。

    7.1、自动释放池代码转换

    代码转换

    objc_autoreleasePoolPush代码

    objc_autoreleasePoolPush

    objc_autoreleasePoolPop代码

    objc_autoreleasePoolPop

    7.2、自动释放池数据结构

    7.2.1、概念
    数据结构

    双向链表

    双向链表


    7.2.2、AutoreleasePoolPage结构
    AutoreleasePoolPage

    由上面可以看到:AutoreleasePool是和线程一一对应的

    AutoreleasePoolPage内存地址:

    内存地址
    7.2.3、AutoreleasePoolPage::push实现
    AutoreleasePoolPage::push

    AutoreleasePoolPage::push相当于是在当中插入哨兵对象,做标记。

    7.2.4、[obj autorelease]实现过程
    autorelease 调用autorelease
    7.2.5、AutoreleasePoolPage::pop
    AutoreleasePoolPage::pop

    相当于是将next指针哨兵对象之间的内容,全部release。

    发送release消息 next指针回退

    7.3、自动释放池总结

    总结

    八、循环引用

    8.1、循环引用类型

    循环引用类型

    8.2、场景

    场景

    8.3、破除循环引用思路

    思路

    8.4、循环引用方案

    方案
    • __weak破解


      __weak
    • __block破解


      __block
    • __unsafe_unretained破解


      __unsafe_unretained

    8.5、循环引用示例

    8.5.1、 Block示例

    参考Block示例

    8.5.2、 NSTimer示例

    先来解释为什么NSTimer能够产生循环引用?


    NSTimer

    1、因为对象拥有NSTimer,所以要对其强引用。
    2、因为NSTimer持有它的target,所以NSTimer强引用对象。
    3、通过对象弱引用NSTimer,达不到目的。
    因为主线程的Runloop,长驻内存➡️Runloop强引用NSTimer➡️NSTimer强引用对象➡️所以当前对象很难释放

    解决方案:

    • 非重复性定时器
    //取消定时器
    [timer invalidate];
    timer = nil;
    
    • 重复性定时器


      重复性定时器

      设置中间对象,判断中间对象所持有的目标对象是否为nil(这里利用到了weak指针会自动为nil)。如果为nil,则执行以下代码:

    //取消定时器
    [timer invalidate];
    timer = nil;
    

    九、内存管理总结

    问题11:什么是ARC?

    ARC是由LLVM编译器和Runtime共同协作,为我们实现自动引用计数管理。

    问题12:苹果是如何实现AutoreleasePool的?

    是以栈为节点通过双向链表的形式组合而成。

    问题13:什么是循环引用?你遇到过哪些循环引用,是怎样解决的?

    上面讲的NSTimer例题就可以。

    相关文章

      网友评论

        本文标题:OC内存管理

        本文链接:https://www.haomeiwen.com/subject/eqprmctx.html