标签:
我是前言
Autorelease机制是iOS开发者管理对象内存的好伙伴,MRC中,调用[obj autorelease]来延迟内存的释放是一件简单自然的事,ARC下,我们甚至可以完全不知道Autorelease就能管理好内存。而在这背后,objc和编译器都帮我们做了哪些事呢,它们是如何协作来正确管理内存的呢?刨根问底,一起来探究下黑幕背后的Autorelease机制。
Autorelease对象什么时候释放?
这个问题拿来做面试题,问过很多人,没有几个能答对的。很多答案都是“当前作用域大括号结束时释放”,显然木有正确理解Autorelease机制。
在没有手加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop
__weak id reference = nil; - (void)viewDidLoad { [super viewDidLoad]; NSString *str = [NSString stringWithFormat:@"sunnyxx"]; // str是一个autorelease对象,设置一个weak的引用来观察它 reference = str; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"%@", reference); // Console: sunnyxx } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"%@", reference); // Console: (null) }
由于这个vc在loadView之后便add到了window层级上,所以viewDidLoad和viewWillAppear是在同一个runloop调用的,因此在viewWillAppear中,这个autorelease的变量依然有值。
- (void)viewDidLoad { [super viewDidLoad]; @autoreleasepool { NSString *str = [NSString stringWithFormat:@"sunnyxx"]; } NSLog(@"%@", str); // Console: (null)}
Autorelease原理
AutoreleasePoolPage
ARC下,我们使用@autoreleasepool{}来使用一个AutoreleasePool,随后编译器将其改写成下面的样子:
void *context = objc_autoreleasePoolPush();
// {}中的代码objc_autoreleasePoolPop(context);
而这两个函数都是对AutoreleasePoolPage的简单封装,所以自动释放机制的核心就在于这个类。
AutoreleasePoolPage是一个C++实现的类
1.AutoreleasePool并没有单独的结构。它是AutoreleasePool通过双向链表的形式连接在一起,对应图片中的parent指针和child指针。
2.AutoreleasePool是与线程一一对应的,图片中的thread指向当前的线程。
3.AutoreleasePoolPage会有2M的大小内存,除开保存自己的实例以外,其它的用来保存autorelease对象。
4.图片中的id *next作为游标指针指向下一个将要add进来的autorelease对象。
5.一个autorelease对象内存空间被占满的时候,会新建下一个autoreleasePage对象,并用链表连接起来,新创建的autorelease对象会被添加到新的autoreleasePage里面。
所以如果当前只有一个autoreleasePool对象,情况如下所示
如上图所示,再插入一个autorelease对象,就要栈满了,会新创建一个page对象,新的autorelease对象会被放在栈底。
所以向一个新的对象发送autorelease对象就是向page里面的插入到next指针位置
释放时刻
每当进行一次objc_AutoreleasePoolPush调用的时候,runtime会添加一个哨兵对象,为nil
objc_autoreleasePoolPush对象的返回值就是这个哨兵对象的地址,被objc_autoreleasePop(哨兵对象)作为入参,于是:
1.根据哨兵对象的地址找到哨兵对象所在的page
2.在当前page中,将晚于哨兵对象都发送一次release操作,并向前移动next到正确位置。
3.从最新加入的对象开始,一直向前清理,可以跨越多个page
刚才的objc_autoreleasePoolPop操作后,变成:
标签:
原文地址:http://www.cnblogs.com/guchengfengyun/p/4525849.html