AutoReleasePool
AutoReleasePool是用来自动释放调用了autoRelease的对象,通过runloop 开始进入runloop,即将休眠,即将退出runloop的时候开始处理AutoReleasePool对象,进行释放。
apple 官方说明在以下情况下使用@autoreleasepool
- 如果你编写的程序不是基于 UI 框架的,比如说命令行工具;
- 如果你编写的循环中创建了大量的临时对象;
- 如果你创建了一个辅助线程。
@autoreleasepool的内部结构
我们使用clang编译一下main.m文件 cd到main.m 的目录 使用clang -rewrite-objc main.m
我们可以看到下面这样的代码,内部其实是调用了objc_autoreleasePoolPush()方法 以及objc_autoreleasePoolPop()方法
结果分析:{}的内部只有一个结构体变量,看看这个结构体,也就是一个初始化函数,析构函数,那么是不是就饿会死意味着这个局部变量的生命周期就是在这个{}的内部,意味着{}开始的时候objc_autoreleasePoolPush(),{}结束的时候objc_autoreleasePoolPop()。
那么这个结构体到底是什么,我们去runtime看看
autorelease释放的流程
- 我们进入到runtime object.mm 我们通过push方法找到这个类AutoreleasePoolPage
结果分析:我们编译之后调用的函数其实是AutoreleasePoolPage调用push()/pop()方法。
那么这个AutoreleasePoolPage是什么呢?其实AutoreleasePoolPage就是用来存储要管理的对象的。我们看一下这个AutoreleasePoolPage的结构体。
我们可以看到AutoreleasePoolPage就是一个双向链表。
为什么说是固定大小呢?这里面我们可以看到规定大小是1<<14也就是2的14次方。可能版本不一样,老版本中是4096个字节。
那么这个push做了什么呢?
一般情况都会走autoreleaseFast方法。那么他到底做了什么呢?
结果分析:开始的时候回去检测有没有poolPage如果有的话就压栈一个POOL_BOUNDARY ,POOL_BOUNDARY相当于每个@autorealsePool的分界线。
那么我们调用autoRealse之后,系统怎么处理呢?
我们可以看到也是通过autoreleaseFast方法将这个obj加入到page中。
那么他是怎么去释放的呢。
我们可以看到这个逻辑就是通过while循环一直去获取对象,执行realse操作。
所以总结:对象的自动释放池其实就是一个个固定大小的双向链表管理的,通过添加POOL_BOUNDARY来分隔多个@autoreleasepool的嵌套。接收到runloop的即将休眠,以及退出的通知 之后执行pop操作,通过next不断去获取obj,执行realse操作释放内存。