iOS日记5-autoreleasepool和autorelease

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多线程和内存管理》

你可能感兴趣的:(iOS日记5-autoreleasepool和autorelease)