Autoreleasepool

308 阅读2分钟

Autorelease机制

Autorelease机制是iOS开发者管理对象内存的好伙伴,MRC中,调用[obj autorelease]来延迟内存的释放是一件简单自然的事,ARC下,我们甚至可以完全不知道Autorelease就能管理好内存。
在没有手加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop

Autorelease原理

苹果在主线程 RunLoop 里注册了两个 Observer: 第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。 第二个 Observer 监视了两个事件: BeforeWaiting(准备进入睡眠) 和 Exit(即将退出Loop), BeforeWaiting(准备进入睡眠)时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池; Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。

内存管理规则

  • 自己生成的对象自己持有
  • 非自己生成的对象,自己也能持有
  • 不再需要自己持有的对象时必须释放
  • 自己不持有的对象无法释放

局部释放池的应用

for (int i = 0; i < largeNumber; i++) {
    
    @autoreleasepool {
        NSString *str = [NSString stringWithFormat:@"hello -%04d", i];
        str = [str stringByAppendingString:@" - world"];
    }
}

要点:

  • [NSString stringWithFormat:@"hello -%04d", i]方法创建的对象会加入到自动释放池里,对象的释放权交给了RunLoop 的释放池
  • RunLoop 的释放池会等待Runloop即将进入睡眠或者即将退出的时候释放一次
  • for循环中线程一直在做事情,Runloop不会进入睡眠

上边的代码for循环生成的NSString对象会无法及时释放,造成瞬时内存占用过大,每次循环时都手动创建一个局部释放池,及时创建,及时释放,这样NSString对象就会及时得到释放

参考资料

www.jianshu.com/p/a2999d772…