美文网首页
ARC / Autoreleasepool

ARC / Autoreleasepool

作者: 桃逸 | 来源:发表于2017-01-10 13:30 被阅读93次

    参考:http://www.jianshu.com/p/1b66c4d47cd7

    在每一个Runloop中,系统会隐式创建一个Autoreleasepool;
    (一个UI事件,Timer call, delegate call, 一个鼠标事件,键盘按下(MAC OSX),或者iphone上的触摸事件,异步http连接下后当接收完数据时,都会创建autoreleasepool???)

    问题

    • auto release 对象什么时候释放?
      参考:http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
      在没有加入autorelease pool情况下,autorelease对象是在当前的runloop迭代结束时释放的;

    • autoreleasepool中的对象,release将延迟到什么时候执行?
      1.当前autoreleasepool结束后,该pool中所有对象会被release;
      2.手动调用drain释放;

    • 系统是什么时候释放的?
      "The Application Kit creates an autorelease pool on the main thread at the beginning of every cycle of the event loop".
      在每一个事件周期的开始,系统会自动创建一个自动释放池,在每一个事件周期的结尾,系统会自动销毁这个自动释放池;
      ARC之前,会在下一轮runloop时,释放这个auto-release pool?

    • autoreleasepool 何时需要手动创建?
      1.当你在主线程开启其他线程;//大多数情况下不需要自己创建线程,可以使用系统的GCD和NSOperation;
      2.在短时间内制造了大量自动释放对象时,及时销毁有助于内存资源合理利用;

    • ARC 中 autoreleasepool
      ARC并不是舍弃了autoreleasepool,而是在编译阶段帮你插入必要的retain/release/autorelease的代码调用;
      ps: 对象并不是自动被加入到当前pool中,而是需要对象发送autorelease消息;

    • ARC下,_weak指向对象被释放了,那么_weak会被自动设置为nil,那么runtime是如何做到这一点的那?
      在内存中维护一张weak表

    {
        id __weak obj1 = obj;
    }
    /* 编译器模拟代码 */
    id obj1;
    objc_initWeak(&obj1, obj);
    objc_destroyWeak(&obj1);
    

    一个对象地址可以对应很多个_weak变量地址,当一个对象被析够时,那么他在weak表中所指向的_weak变量就会被置为nil,然后再weak表中删除该记录;
    由于使用weak变量会造成以上系统开销,所以要仅在需要时才使用;

    • ARC下如何获取retainCount
      使用_objc_rootRetainCount(obj);

    实现原理

    详情可以参考autoreleasepool的objc源码
    @autoreleasepool {} 实际上是两个函数的调用:
    objc_autoreleasePoolPush
    objc_autoreleasePoolPop
    这两个函数都调用了AutoreleasePoolPage类中的方法,也就是说他们是通过AutoreleasepoolPage实现的;
    阅读源码可知,AuoreleasePoolPage的定义中有如下属性:

     magic_t const magic; //校验结构完整
     id *next; //指向栈顶
     pthread_t const thread; //指向当前线程
     AutoreleasePoolPage * const parent; //指向父节点
     AutoreleasePoolPage *child; //指向子节点
     uint32_t const depth; //链表的深度,即链表节点的个数
     uint32_t hiwat; //hight water mark 最高水位标记,栈对象做多时候的个数
    

    这个类有parent跟child节点,可以推断出这个一个双向链表的节点,而实际上Autoreleasepool的内存结构就是一个双向链表;
    也就是说一个线程的autoreleasepool就是一个指针栈,栈中存放的指针指向加入其中的需要release的对象或者POOL_SENINEL(哨兵对象, 用不分割autoreleasepool);
    哨兵对象是在入栈时加入的一个autoreleasepool的标记,当autoreleasepool进行出栈时,每一个比这个哨兵对象后进栈的对象都会release;
    这个栈是由一个以page为节点的双向链表组成,page根据需求进行增减;若是一个page已存满autorelease对象,则新建一个page;
    autorelease函数和push函数一样,都是通过autoreleaseFast函数想自动释放池中添加一个对象,不过push函数的入栈是一个哨兵对象,而autoreleas函数入栈的是需要加入autoreleasepool的对象;

    相关文章

      网友评论

          本文标题:ARC / Autoreleasepool

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