结构:简单说是双向链表,每张链表头尾相接。每创建一个池子,会在首部创建一个 哨兵 对象,作为标记。最外层池子的顶端会有一个next指针。当链表容量满了,就会在链表的顶端,并指向下一张表。
1、Autorelease 概述
当向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。
它仍然是个正当的对象,因此 自动释放池定义的作用域内 的其它对象可以向它发送消息。
当自动释放池释放时,其中所有被管理对象都会收到”release”的消息, 从而池中的所有对象也就被释放。
注意,同一个对象可以被多次调用”autorelease”方法,并可以放到同一个”AutoreleasePool”中。 所以引入这个自动释放池机制,对象的”autorelease”方法代替”relrease”方法可以延长它的生命周期,直接到当前”AutorelreasePool”释放。
很多人说, 当程序执行到作用域结束的位置时(当前作用域大括号结束时),自动释放池就会被释放,这个说法是不对的。正确的过程是如何呢?
iOS的运行时是由一个一个runloop组成的,每个runloop都会执行下图的一些步骤:

可以看到,每个runloop中都创建一个Autorelease Pool,并在runloop的末尾进行释放,所以,一般情况下,每个接受autorelease消息的对象,都会在下个runloop开始前被释放。
也就是说,在一段同步的代码中执行过程中,生成的对象接受autorelease消息后,一般是不会在作用域结束前释放的。
所以严谨的说, 在没有手动添加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop。
2、AutoreleasePool 与 RunLoop
App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。
第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是 -2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
retained return value,例如[[NSString alloc] initWithFormat:],
而其他的则是unretained return value
对于前者调用者是要负责释放的,后者不需要负责释放
总结:
1.方法里的临时变量是会通过autoreleasepool释放的
2.NSCFString跟普通对象一样是可以释放的
3.NSString和NSArray的工厂方法可以延长对象的生命周期(同理,NSDictionary也是一样的,有兴趣的可以试一下)
在ARC下,已经不允许使用NSAutoreleasePool对象了,并且根据官方文档,@autoreleasepool比它更高效,因此这里只讨论@autoreleasepool。
最重要的两个入口函数如下:
void *
objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
void
objc_autoreleasePoolPop(void *ctxt)
{
AutoreleasePoolPage::pop(ctxt);
}
push操作往poolpage中插入一个标记,
而pop则给这一区间的所有对象发送release消息。
有一种说法是:
这一种说法的原因是,
在主线程,当前runloop,可以明显看到注册了几种observer
activities = 0x1,对应的就是kCFRunLoopEntry;
activities = 0xa0,对应的就是kCFRunLoopBeforeWaiting | kCFRunLoopExit
它们的回调函数为_wrapRunLoopWithAutoreleasePoolHandler (),这个函数在entry的时候调用push(),在beforeWaitting的时候调用pop()和push(),在exit时调用pop
总结
@autoreleasepool{}复制代码等价于
void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);OC的内存管理
每当碰到release和autorelease的时候引用计数就会减一,如果此对象的计数变为了0, 就会被系统销毁.