1.autoreleasePool的具体使用
MRC:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain]; //调用[obj release]
ARC和MRC:
@autoreleasepool {
id obj = [[NSObject alloc] init];
}
2.autoreleasepool原理
1)与NSRunLoop的关系
每一个线程(包括主线程)都有一个NSAutoreleasePool栈. 当一个新的池子被创建的时候, push进栈. 当池子被释放内存时, pop出栈. 对象调用autorelease方法进入栈顶的池子中. 当线程结束的时候, 它会自动地销毁掉所有跟它有关联的池子.
在当前的runloop迭代中,系统会加入autoreleasepool的push和pop操作,用于管理对象。
2)内部实现
这里涉及到了一个AutoreleasePoolPage类。
//非完整实现
struct AutoreleasePoolPage {
magic_t const magic;
id *next;
pthread_ const thread;
AutoreleasePoolPage *const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
}
- AutoreleasePool并没有单独的结构,而是由若干个AutoreleasePoolPage以双向链表的形式组合而成(分别对应结构中的parent指针和child指针)
- AutoreleasePool是按线程一一对应的(结构中的thread指针指向当前线程)
- AutoreleasePoolPage每个对象会开辟4096字节内存(也就是虚拟内存一页的大小),除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址
- 上面的id *next指针作为游标指向栈顶最新add进来的autorelease对象的下一个位置
- 一个AutoreleasePoolPage的空间被占满时,会新建一个AutoreleasePoolPage对象,连接链表,后来的autorelease对象在新的page加入
使用@autoreleasepool{ }时,编译器将其改写为:
void *context = objc_autoreleasePoolPush(); //作为一个记录点,每一次的释放会将2个记录点内的对象都释放,直到完全释放
//some codes
objc_autoreleasePoolPop(context);
3.需要手动创建autoreleasepool的时候
- 1.写的程序不是基于UIFrameWork,例如命令行项目
- 2.写的循环大量创建临时对象。可以在循环中创建autoreleasepool,在池子中创建对象。这样有助于降低内存峰值
- 3.创建了一个新的线程,线程开始执行时,需要立刻创建一个autoreleasepool
4.参考资料
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
http://www.jianshu.com/p/5559bc15490d
《Objective-C高级编程:ios与OS X多线程和内存管理》
网友评论