自动释放池有什么用?
自动释放池的数据结构
以栈为结点通过双向链表的形式组合而成且和线程一一对应的
AutoReleasePool工作流程
AutoReleasePool是OC的内存自动回收机制,将加入到AutoReleasePool中的变量release时机延迟。在正常情况下,创建的变量会在超出其作用域的时候release,但是如果将变量加入AutoreleasePool,那么release将延迟执行,即使超出作用域也不会立即释放,直到runloop休眠或者超出AutoReleasePool作用域才会释放。
程序启动到加载完成,主线程对应的Runloop处于休眠状态,直到用户点击交互唤醒Runloop,用户每次交互都会启动一次Runloop用来处理用户的点击、交互事件,Runloop被唤醒后,会自动创建AutoReleasePool,并将所有延迟释放的对象添加到AutoReleasePool,在一次完整的Runloop执行结束前,会自动向AutoReleasePool中的对象发送release消息,然后销毁AutoReleasePool。

该结构体提供了一个构造函数objc_autoreleasePoolPush和一个析构函数objc_autoreleasePoolPop。所以自动释放池在底层其实是一个结构体,其通过objc_autoreleasePoolPush完成自动释放池的创建,objc_autoreleasePoolPop来释放自动释放池。
调用了autorelase的对象都是最终都是通过AutoreleasePoolPage来管理的,AutoreleasePoolPage的结构体如下:

AutoreleasePoolPage中Push方法的内部实现

我们push操作,会把当前next的位置置为nil,也叫做哨兵对象,然后将next指针指向下一个可入栈的位置。
实际上每次进行AutoreleasePool的代码块创建的时候,相当于不断的在栈中去插入哨兵对象。
[obj autorelease]方法实现
当我们调用了一个对象的autorelease,首先会判断当前next指针是否指向栈顶,若没有指向栈顶,则直接把对象添加到当前栈的next位置。
假如当前next已经位于栈顶,那么当前AutoreleasePoolPage就没办法添加新的autorelease对象了,于是需要增加一个栈结点拼接到链表上,之后再新的栈上面添加对象。
AutoreleasePoolPage中Pop方法的内部实现
根据传入的哨兵对象来找到pop的对应位置。
给上次push操作之后添加的对象依次发送release消息。
autoreleasePool的多层嵌套调用
就是多次插入哨兵对象,当我们每次进行autoreleasePool代码块创建的时候,系统就会为我们进行哨兵对象的插入。
autoreleasePool的使用场景:
在for循环中alloc出大量的图片数据等内存消耗较大,需要在for循环内部手动插入autoreleasePool,每一次for循环,都进行一次内存的释放,来降低内存的峰值。