美文网首页
iOS 内存管理

iOS 内存管理

作者: 星空WU | 来源:发表于2021-03-15 15:01 被阅读0次

    自动释放池

    AutoreleasePool的实现原理是怎么样的?

    AutoreleasePool是以栈为结点,通过双向链表的形式组合而成的数据结构。编译器会将@autoreleasepool{}改写,如下 图。实际objc_autoreleasePoolPop函数在内部做了pop操作,批量将autoreleasepool中的所有的对象都会做一次release操作。

    编译器改写@autoreleasepool{}

    下面对上面的主要函数进行一个简单的说明

    AutoreleasePool的结构

    1)是以栈为结点通过双向链表的形式组合而成

    2)是和线程一一对应的

    [obj autorelease]的实现(对象加入自动释放池)

    先判断当前next指针是否指向栈顶,如果不是直接加入;如果是,则增加一个栈结点到链表上,在新的栈添加对象;移动next指针

    AutoreleasePoolPage::push实现流程(释放池多层嵌套)

    插入哨兵对象

    AutoreleasePoolPage::pop实现流程(与push相反)

        根据传入的哨兵对象找到对应的位置

        给上次push操作之后添加的对象依次添加release消息

        回退next指针到正确的位置

    AutoreleasePool为何可以嵌套使用?

    多次插入哨兵对象,也就是对一个新的releasePool的创建,如果当前栈没有满,则不需要创建新的page,如果满了,新增一个栈节点

    下面这个图中,array对象在什么时候释放呢?

    在当次runloop将要结束的时候调用AutoreleasePoolPage:pop(),对array对象执行release操作。

    AutoreleasePool的使用场景?

    在for循环中,alloc图片数据等内存消耗较大的场景手动插入autoreleasePool,每一次for循环都进行一次内存的释放,降低内存消耗。

    常见的循环引用以及破除方法:

    代理(delegate)

    block

    NSTimer

    大环引用

    如何破除循环引用?

    __weak

    __block

    __unsafe_unretained(与weak等效)

    __block在ARC和MRC条件下的区别

    MRC下,__block修饰对象不会增加其引用计数,避免了循环引用

    ARC下,__block修饰对象会被强引用,无法避免,需手动破环

    NSTimer  循环引用解决

    如果没有其他处理,只是单纯地在dealloc中写定时器的销毁方法,在退出当前控制器后,由于定时器的循环引用问题导致当前类没有释放销毁,也就不会走dealloc 方法,所以退出控制器后定时器仍然在执行。

    1)在退出界面时手动调用定时器销毁的方法。

    2)引入中间者

    3) 高级中间者

    此时我们需要借助一个虚基类NSProxy,(NSProxy其主要用来消息转发的处理)

    4、带block的timer

    在我们创建timer的时候,苹果也意识到NSTimer的api是存在一定问题的,所以在iOS10.0之后提供了一种block的方法来去解决NSTimer的循环引用的问题.

    相关文章

      网友评论

          本文标题:iOS 内存管理

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