Autoreleasepool概念
autorelease
:即延迟释放。本质上就是延迟调用release
方法。
Autoreleasepool作用
在程序执行完毕即池子即将销毁的时候会对池子中所有调用autorelease
的对象进行一次release
操作。
Autoreleasepool原理
- 程序运行 -> 开启事件循环 -> 发生触摸事件 -> 创建自动释放池 -> 处理触摸事件 -> 事件对象加入自动释放池 -> 一次事件循环结束, 销毁自动释放池。
- 在没有手动加
Autorelease Pool
的情况下,Autorelease
对象是在当前的runloop
迭代结束时释放的,而它能够释放的原因是系统在每个runloop
迭代中都加入了自动释放池Push
和Pop
。
苹果官方文档解释
苹果官方文档 :
The Application Kit creates an autorelease pool on the main thread at the beginning of every cycle of the event loop, and drains it at the end, thereby releasing any autoreleased objects generated while processing an even
在开始每一个事件循环之前系统会在主线程创建一个自动释放池, 并且在事件循环结束的时候把前面创建的释放池释放, 回收内存。
当然也有让autorelease提前生效的办法:自己创建Pool并进行释放。
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray * array = [[NSArray alloc] init] ;
[pool drain];
上面的array就会在[pool drain]执行时被释放。不过只能是在MRC下。
autorelease pool 栈
每一个线程(包括主线程)都有一个NSAutoreleasePool栈. 当一个新的池子被创建的时候, push进栈. 当池子被释放内存时, pop出栈. 对象调用autorelease方法进入栈顶的池子中. 当线程结束的时候, 它会自动地销毁掉所有跟它有关联的池子.
autoreleasepool
我们对@autoreleasepool {}并不陌生,只要在Xcode里创建一个工程,就能看到下面这样的代码:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
main 函数的主体都被 @autoreleasepool 的Block块包在里面,也就是说,接下来所有的对象创建都在这个block里面。
那么, @autoreleasepool 的作用到底是什么呢?我们开发中可以用它来做什么呢?
-
可以在某些情况下,大幅度降低程序的内存占用,如图所示:
NSThread、NSRunLoop 和 NSAutoreleasePool
- 每一个线程,包括主线程,都会拥有一个专属的
NSRunLoop
对象,并且会在有需要的时候自动创建。 - 在主线程的
NSRunLoop
对象(在系统级别的其他线程中应该也是如此,比如通过dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 获取到的线程)
的每个event loop
开始前,系统会自动创建一个autoreleasepool
,并在event loop
结束时drain
。 - 另外,
NSAutoreleasePool
中还提到,每一个线程都会维护自己的autoreleasepool
堆栈。换句话说autoreleasepool
是与线程紧密相关的,每一个autoreleasepool
只对应一个线程。
Autoreleasepool总结
通常情况下,我们是不需要手动添加autoreleasepool
的,使用线程自动维护的 autoreleasepool 就好了。
根据苹果官方文档中对 Using Autorelease Pool Blocks 的描述,我们知道在下面几种种情况下是需要我们手动添加 autoreleasepool
的:
- 写基于命令行的的程序时,就是没有UI框架,如AppKit等Cocoa框架时。
- 如果你编写的循环中创建了大量的临时对象;
- 创建了新的线程。(非Cocoa程序创建线程时才需要)。
- 长时间在后台运行的任务。
参考文章:
iOS基础 - autorelease 和 autoreleasepool
黑幕背后的Autorelease
@autoreleasepool-内存的分配与释放