目录
- 对象调用autorelease发生了什么
- autorelease对象什么时候释放
- autorelease与runloop的关系
- 苹果是怎么实现autorelease
- 参考连接
对象调用autorelease发生了什么
自己生成并持有了一个对象id obj = [obj alloc] init
,调用autorelease[obj autorelease]
。这样我们虽然前面生成并取得对象的存在,但调用autorelease后我们自己就不持有对象,后续不需要自己调用release释放。
但调用autorelease后发生了什么呢?
autorelease提供这样的功能,使对象超出作用域后,能自动正确的释放(调用release)。
像“自己生成但不持有对象”这类系统方法的实现就是加入了autorelease。例如:
[NSString stringWithFormat:@"sunnyxx"]
[NSArray array]
其内部的实现是先通过alloc\new\copy\mutableCopy
生成并持有对象,然后调用autorelease
,从而达到自己生成但不持有对象的效果。
autorelease对象什么时候释放
在超出对象作用范围后,在他所在的runloop迭代结束的时候会被释放。runloop迭代结束时,runloop会释放其生成的autoreleasepool,对象加入的就是最近的对象所在线程的runloop的autoreleasepool中。
autorelease与runloop的关系
runloop在开始下一个迭代的时候会生成一个autoreleasepool,在这个迭代结束后会释放autoreleasepool。所以我们平时在主线程不需要自己管理autoreleasepool,线程中有成对的存在。
App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。
第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
摘自 深入理解RunLoop
在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。
苹果是怎么实现autorelease
应用
for循环中遍历产生大量autorelease变量时,就需要手加局部AutoreleasePool。
优化前的代码
for (int i = 0; i < 图像数;++i) {
/*
读入图像
大量产生autorelease的对象
由于没有废弃NSAutoreleasePool对象
这些autorelease的对象一直存在
导致内存不足
*/
}
优化后的代码
for (int i = 0; i < 图像数;++i) {
NSAutoreleasePool *pool = [[NSAutorealsePool alloc] init];
/*
读入图像
大量产生autorelease的对象
*/
[pool drain];
/*
主动释放
*/
}
参考连接
- 深入理解RunLoop
- 黑幕背后的Autorelease
- 面试题有有关autorelease的题目
网友评论