美文网首页
@autoreleasepool

@autoreleasepool

作者: J星O海E | 来源:发表于2021-07-04 00:09 被阅读0次

    主线程autoreleasepool的创立和释放时机

    App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。

    第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。

    第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。

    autoreleasepool的实现

    自动释放池是由 AutoreleasePoolPage 以双向链表的方式实现的

    当对象调用 autorelease 方法时,会将对象加入 AutoreleasePoolPage 的栈中

    调用 AutoreleasePoolPage::pop 方法会向栈中的对象发送 release 消息

    POOL_BOUNDARY是一个边界对象 nil,之前的源代码变量名是POOL_SENTINEL哨兵对象,用来区别每个page即每个AutoreleasePoolPage边界

    AutoreleasePoolPage::push()

    调用push方法会将一个POOL_BOUNDARY入栈,并且返回其存放的内存地址.

    push就是压栈的操作,先加入边界对象,然后添加person1对象,然后是person2对象...以此类推

    AutoreleasePoolPage::pop(ctxt);

    调用pop方法时传入一个POOL_BOUNDARY的内存地址,会从最后一个入栈的对象开始发送release消息,直到遇到这个POOL_BOUNDARY(因为是双向链表,所以可以向上寻找)

    什么时候需要自己创建 @autoreleasepool?

    写循环,循环里面包含了大量临时创建的对象。

    ARC 环境下,需不需要手动添加 @autoreleasepool?

    通常不需要,因为主线程已经帮我们建了autoreleasepool

    AutoreleasePoolPage

    AutoreleasePoolPage是一个C++实现的类

    AutoreleasePool并没有单独的结构,而是由若干个AutoreleasePoolPage以双向链表的形式组合而成(分别对应结构中的parent指针和child指针)

    AutoreleasePool是按线程一一对应的(结构中的thread指针指向当前线程)

    AutoreleasePoolPage每个对象会开辟4096字节内存(也就是虚拟内存一页的大小),除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址

    上面的id *next指针作为游标指向栈顶最新add进来的autorelease对象的下一个位置

    一个AutoreleasePoolPage的空间被占满时,会新建一个AutoreleasePoolPage对象,连接链表,后来的autorelease对象在新的page加入

    相关文章

      网友评论

          本文标题:@autoreleasepool

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