Autorelease Pool是Objective-C中的内存管理方式之一,它与线程和NSAutorelease类有关。每一个线程都拥有自己的Autorelease Pool栈,这个栈底层是由双向链表构成,而双向链表由类AutoreleasePoolPage表示。AutoreleasePoolPage是一个C++类,这个类的结构如下(只给出了部分相关成员变量):

class AutoreleasePoolPage  {
static pthread_key_t const key = AUTORELEASE_POOL_KEY; //和线程相关的key值
static size_t const SIZE =
#if PROTECT_AUTORELEASEPOOL
PAGE_MAX_SIZE; // must be multiple of vm page size
#else
PAGE_MAX_SIZE; // size and alignment, power of 2
#endif
static size_t const COUNT = SIZE / sizeof(id); //每一个page的大小
id *next; //加入当前page中的Objective-C对象地址会传给next
pthread_t const thread; //线程的引用
AutoreleasePoolPage * const parent; //指向父节点
AutoreleasePoolPage *child; //指向子节点
};

线程与Autorelease Pool栈的关系如下图所示:

上图中,加颜色部分表示加入到自动释放池中的对象,而next总是指向下一个可用位置。当前线程总是可以通过AutoreleasePoolPage中的key属性获取到位于栈最顶端(图中就是最右边)的AutoreleasePoolPage对象,这个对象被称为hot page。

需要注意的是,并不是一个AutoreleasePoolPage对象就代表一个自动释放池,一个自动释放池可以横跨多个AutoreleasePage对象。自动释放池之间是通过哨兵(Sentinel)来分隔的。那么什么是哨兵,NSAutoreleasePool对象和AutoreleasePoolPage对象之间又有什么关系呢?

当我们使用如下方法创建NSAutoreleasePool对象时:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSAutoreleasePool对象的init方法实际上会调用AutoreleasePoolPage类的static push方法:

  static inline void *push()
{
id *dest = autoreleaseFast(POOL_SENTINEL);
assert(*dest == POOL_SENTINEL);
return dest;
}

AutoreleasePoolPage::push方法中的autoreleaseFast方法传入的就是一个哨兵,其实就是一个nil值。而AutoreleasePoolPage::autoreleaseFast方法会做3件事:

1 通过AutoreleasePoolPage的key属性获取当前线程对应的hot page,如果hot page存在并且未满,那么就向当前page中加入哨兵;

2 如果当前hot page已满,那么就创建一个新的AutoreleasePoolPage对象,加入到链表最顶端使成为hot page,并将哨兵加入到新的hot page中;

3 如果hot page根本不存在,那么也会创建一个新的AutoreleasePoolPage对象,使之成为hot page,并将哨兵加入到新hot page中。

当加入了一个哨兵之后,就代表一个新自动释放池开始。AutoreleasePoolPage::push方法会将这个哨兵地址返回回去,而NSAutoreleasePool对象会持有这个哨兵地址:

@interface NSAutoreleasePool : NSObject {
@private
void *_token; //保存哨兵地址
void *_reserved3;
void *_reserved2;
void *_reserved;
}

NSAutoreleasePool对象当中的_token成员,就是用来保存哨兵地址的。因此,线程,AutoreleaesPoolPage对象,NSAutoreleasePool对象之间的关系可以表示成:

上图中有两个哨兵,因此有两个自动释放池,第一个自动释放池由NSAutoreleasePool对象_1表示,范围从第一个哨兵开始到第二个哨兵下面,第二个自动释放池由NSAutoreleasePool对象_2表示,范围从第二个哨兵开始直到结束。这也是自动释放池嵌套时的情形。

当自动释放池释放,即调用NSAutoreleasePool对象的release或者drain时会发生什么情况呢?

当调用NSAutoreleasePool对象的release或者drain方法时,它们将NSAutoreleasePool对象保存的哨兵地址传递会给AutoreleasePoolPoage的static pop方法,这个AutoreleasePoolPage::pop方法主要做了如下2件事:

1 通过相应算法,根据哨兵地址找到哨兵所在的AutoreleasePoolPage对象;

2 从hot page开始,直到哨兵对象为止,依次弹出加入到里面的Objective-C对象,并且向Objective-C对象发送release消息

假设释放了上面的NSAutoreleasePool对象_2,那么结果如下图所示:

从Apple关于NSAutoreleasePool的官方文档我们可以知道,NSAutoreleasePool对象无法被retain,因此,当AutoreleasePoolPage::pop方法调用完成之后,NSAutoreleasePool对象的release或者drain方法就会释放掉这个NSAutoreleasePool对象本身。到这里为止,我们又可以向上一个自动释放池当中添加新的Objective-C对象了。

Autorelease Pool-自动释放池的更多相关文章

  1. objective-C 的内存管理之-自动释放池(autorelease pool)

    如果一个对象的生命周期显而易见,很容易就知道什么时候该new一个对象,什么时候不再需要使用,这种情况下,直接用手动的retain和release来判定其生死足矣.但是有些时候,想知道某个对象在什么时候 ...

  2. Autorelease自动释放池的使用

    Autorelease自动释放池的使用 使用ARC开发,只是在编译时,编译器会根据代码结构自动添加了retain.release和autorelease. MRC内存管理原则:谁申请,谁释放 遇到al ...

  3. OC中对象元素的引用计数 自动释放池的相关概念

    OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc]  view plaincopy 1. //   2. / ...

  4. C++模拟OC的多重自动释放池

    使用过OC的都知道,OC的引用计数机制用起来还比较方便.于是就仿照OC的形式搞了个C++引用计数. 支持多重自动释放池,每次autorelease都会放到栈顶的自动释放池中. 自动释放池也可以像变量一 ...

  5. autoreleasepool 自动释放池的理解

    常见的面试题:以下代码存在什么样的问题?应该如何改进? for (int i = 0; i < 100000; i++) { NSString *str = @"abc"; ...

  6. 自动释放池的前世今生 ---- 深入解析 autoreleasepool

    http://draveness.me/autoreleasepool.html 关注仓库,及时获得更新:iOS-Source-Code-Analyze Follow: Draveness · Git ...

  7. Objective-C中的自动释放池

    自动释放池块@autoreleasepool 自动释放池块在MRC和ARC下都可以使用.在MARC下,为了将自动释放池块内部的变量放入自动释放池,需要手动调用autorelease方法:在ARC下,只 ...

  8. 63 (OC)* NSAutoreleasePool 自动释放池

    目录 0:ARC 1: 自动释放池 2:NSAutoreleasePool实现原理 3:autorelease 方法 4: Runloop和Autorelease的关系 5: Using Autore ...

  9. OC学习篇之---数组对象的引用计数问题和自动释放池的概念

    之前一片文章中我们介绍了OC中的两个关键字@property和@synthesize的使用的使用: http://blog.csdn.net/jiangwei0910410003/article/de ...

随机推荐

  1. SMBUS(IIC)总线

    1.SPI和IIC一般都作为板上通信,UART.SMBUS和USB一般都作为板间通信. 其中SMBUS是参考IIC制定出来的眼生病,两者很像. 2.SMBUS的I/O接口是由两条线组成的双向串行总线. ...

  2. 在js中使用json

    在js中使用json var obj = {     "1" : "value1",     "2" : "value2" ...

  3. vim 多行注释

    多行注释: 1. 进入命令行模式,按ctrl + v进入 visual block模式,然后按j, 或者k选中多行,把需要注释的行标记起来 2. 按大写字母I,再插入注释符,例如// 3. 按esc键 ...

  4. memcached的安装

    最近在研究怎么让Discuz!去应用Memcache去做一些事情,记录下Memcache安装的过程. Linux下Memcache服务器端的安装 服务器端主要是安装memcache服务器端,目前的最新 ...

  5. Spark学习笔记-如何运行wordcount(使用jar包)

    IDE:eclipse Spark:spark-1.1.0-bin-hadoop2.4 scala:2.10.4 创建scala工程,编写wordcount程序如下 package com.luoga ...

  6. 2014年总结:我的IT路

    又是一年春节时,转眼之间已经毕业4年,简单回顾一下这几年的职业生涯,希望大家提出宝贵意见. 大学时,几个同学跟着学校网络中心的老师一块做校园网上运行的小系统.偶尔协助一下老师对学校机房.校园网做一下维 ...

  7. #Java编程题-百钱百鸡

    问题: 百钱百鸡问题.用100钱买100只鸡,公鸡一只五钱,母鸡一只三钱,雏鸡三只一钱,编程计算共有几种买法(要求每种鸡至少要买1只). 自己的实现,没有什么数据结构,算法,求大神指点!! packa ...

  8. Linux安装oracle报错解决

    安装报错:[oracle@centos1 database]$ ./runInstaller Starting Oracle Universal Installer... Checking insta ...

  9. Visual Studio 2013 Professional Key

    今天发现家里的VS2013专业版过期了,于是google百度一顿大搜,多数key都不能用,不过还是找到一个key可以使用的. Visual Studio 2013 Professional Key: ...

  10. WPF用样式实现TextBox的虚拟提示效果

    [版权声明]本文为博主原创,未经允许禁止用作商业用途,如有转载请注明出处. 话说好多软件和网站都能实现虚拟提示,好吧这个名词是我自己起的,因为我也不知道这么形容这个效果. 效果描述:在TextBox没 ...