• ARC的原理详解


    1,ARC的本质

    ARC本质是NSAutoreleasePool的直接应用,

    @autorelease{

    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

    }

    其实是:

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    int iRet = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

    [pool release];

    然后,各种allocrelease后,对应refcount都设置成0,在出自己的引用范围后,就背nsautoreleasepool自动的释放掉,如下:

    NSString* str = [[[NSString alloc] init] autorelease];

    .......

    其中str已经进行了autorelease,当结束生命周期后,str直接释放掉。

    2,NSAutoreleasePool的原理

    AutoreleasePoolPage是一个C++实现的类。

    typedef struct{
    magic_t const magic;
    id* next;
    pThread_t* thread;
    AutoreleasePoolPage* Parent;
    AutoreleasePoolPage* Child;
    uint32_t const depth;
    uint32_t hiwat;
    }
    其中:
    1,magic是魔术数字,划分内存边界,数据结构起始处;
    2,next,是指向该AutoreleasePool的边界;
    3,thread, 是该AutoreleasePool的线程,每个线程有自己的AutoreleasePool;
    4,Parent、child,用于建立链表,一个AutoreleasePool不一定足够;
     
    每个NSAutoreleasePool都是4096bytes,不够的就申请新的NSAutoreleasePool,用child, parent连接起来,见上图:
    1,“类实例所占内存”就是数据接口NSAutoreleasePool的空间;
    2,“id objx”, 就是各个申请的对象指针;
    3,next,指的是堆栈顶处;
    对象是如何申请的?

    图中的情况,这一页再加入一个autorelease对象就要满了(也就是next指针马上指向栈顶),这时就要执行上面说的操作,建立下一页page对象,与这一页链表连接完成后,新page的next指针被初始化在栈底(begin的位置),然后继续向栈顶添加新对象。

    所以,向一个对象发送- autorelease消息,就是将这个对象加入到当前AutoreleasePoolPage的栈顶next指针指向的位置

    对象是如何释放的?
    每当进行一次objc_autoreleasePoolPush调用时,runtime向当前的AutoreleasePoolPage中add进一个哨兵对象,值为0(也就是个nil),那么这一个page就变成了下面的样子:

    objc_autoreleasePoolPush的返回值正是这个哨兵对象的地址,被objc_autoreleasePoolPop(哨兵对象)作为入参,于是:

    1.根据传入的哨兵对象地址找到哨兵对象所处的page

    2.在当前page中,将晚于哨兵对象插入的所有autorelease对象都发送一次- release消息,并向回移动next指针到正确位置

    3.补充2:从最新加入的对象一直向前清理,可以向前跨越若干个page,直到哨兵所在的page

    刚才的objc_autoreleasePoolPop执行后,最终变成了下面的样子:

    68.jpg

    嵌套的AutoreleasePool

    知道了上面的原理,嵌套的AutoreleasePool就非常简单了,pop的时候总会释放到上次push的位置为止,多层的pool就是多个哨兵对象而已,就像剥洋葱一样,每次一层,互不影响。

  • 相关阅读:
    rbac 授权
    docker overlayfs k8s overlayfs 目录文件太大
    pod oom
    文档怎么写
    fabric
    nacos 报错 Unknown column 'encrypted_data_key' in 'field list'
    【Oracle】RAC在启动时ohasd超时导致启动失败
    【SQLServer】查看sqlserver中的历史查询记录
    【Oracle】High CPU (%sys) Usage On Oracle Linux 6 UEK3 RAC Node
    【MySQL】MySQL 5.7中过滤复制和部分复制的变化
  • 原文地址:https://www.cnblogs.com/runner42/p/5031154.html
Copyright © 2020-2023  润新知