iOS中的autorelease

目录

  • 对象调用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的题目

你可能感兴趣的:(iOS中的autorelease)