博客迁移--iOS中autoreleasepool自动释放池的研究

前言
写此文章是因为很久之前的一次面试,面试官问我AutoreleasePool用的多不多,当时距离上次工作有些时日,又一直在家带孩子,突然去,有点懵,现在来复习下吧

正文

AutoreleasePool:自动释放池,双向链表结构,在代码中会被解析成如下这样

void *context = objc_autoreleasePoolPush();
// {}中的代码
objc_autoreleasePoolPop(context);//当前runloop迭代结束时进行pop操作

这两个函数实际上都是对AutoreleasePoolPage的封装,参考sunnyxx的博客,AutoreleasePoolPage的结构如下:


博客迁移--iOS中autoreleasepool自动释放池的研究_第1张图片
image

AutoreleasePool是按线程一一对应的(结构中的thread指针指向当前线程)
AutoreleasePool本身并没有单独的结构,其本质是由若干个AutoreleasePoolPage以双向链表形式组成,每个AutoreleasePoolPage则是栈结构,而next指向当前栈顶的下个位置,即指向栈顶最新add进来的autorelease对象的下一个位置
AutoreleasePoolPage每个对象会开辟4096字节内存(也就是虚拟内存一页的大小),除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址
添加对象的时候,一个AutoreleasePoolPage的空间被占满时,会新建一个AutoreleasePoolPage对象,连接链表,后来的autorelease对象在新的page加入,与这一页链表连接完成后,新page的next指针被初始化在栈底(begin的位置),然后继续向栈顶添加新对象。

再说说AutoreleasePool的释放时机,可以分为两种情况:一是系统添加的,那么则跟随当前线程的runloop,runloop结束时释放,因为编译器在每个runloop中开始时加入了自动释放池的Push和结束时加入了Pop;二是手动添加的,那就是在{}结束时就释放啦,出了作用域。

其他Autorelease相关知识点

使用容器的block版本的枚举器时,内部会自动添加一个AutoreleasePool:

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    // 这里被一个局部@autoreleasepool包围着
}];

当然,在普通for循环和for in循环中没有,所以,还是新版的block版本枚举器更加方便。for循环中遍历产生大量autorelease变量时,就需要手加局部AutoreleasePool咯

参考:http://blog.sunnyxx.com/2014/10/15/behind-autorelease/

你可能感兴趣的:(博客迁移--iOS中autoreleasepool自动释放池的研究)