翻译自:

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html%23//apple_ref/doc/uid/20000047-SW4

Autorelease pools提供了一个延迟向对象发送release消息的机制。当你想放弃一个对象的所有权,但是又不想这个对象马上被释放时(比如当你从一个方法中返回一个对象),这种机制是有用的。一般你不需要创建自己的autorelease pools,但是有的时候你必须自己创建autorelease pools,有的时候自己创建autorelease pools会带来便利。

关于Autorelease pools

一个autorelease pool是一个NSAutoreleasePool的实例,它包含收到autorelease消息的对象。当一个autoreleasepool被销毁的时候,它向所包含的每个对象发送一个release消息。一个对象可以放入autorelease pool多次;一个对象每次被放入pool中时都会收到一个release消息(发送一个autorelease消息)。

Autorelease pools以栈的形式进行组织,这通常被称为嵌套的方式。如果你创建了一个新的autorelease pool,它被添加到栈的顶端。当pools被销毁的时候,它们被从栈中移除。当一个对象发送一个autorelease消息时,它被添加到当前线程的Autorelease pools的最顶端的pool中。

Cocoa总是期望一个autoreleasepool是可用。如果一个pool是不可用的,被自动释放的的对象最终不会被释放,这样你的应用就会泄露内存。当一个pool不可用时,如果向一个对象发送autorelease消息,Cocoa会记录一个适当的错误信息。在每一个事件循环(event-loop)开始的时候(比如鼠标按下事件或者一个手势),AppKit和UIKit框架会自动地创建一个pool,并且在事件处理结束时销毁这个pool。(译者注:这个是object-c内存管理的一个核心)因此,一般你不需要自己创建一个pool,甚至没有必要去看创建pool的代码。然而,这里有3中情况你应该创建自己的autorelease pools:

l   你写的程序不是基于UIFramework,比如一个命令行工具。

l   你写了一个循环,里面创建了大量的临时变量。

在下次事件循环之前,你可以在这个循环中创建一个autorelease pool用于处理这些临时变量。在循环中使用autorelease pool帮助降低应用程序占用的内存峰值。

l   你生成了一个线程。

线程一开始执行,你就必须创建你自己的autorelease pool;不然,你的应用就会泄露对象。(“Autorelease Pools and Threads”查看更多细节)

你使用alloc和init消息创建一个NSAutoreleasePool对象,使用drain消息销毁这个对象。如果你向一个autorelease pool发送autorelease或retain消息则会触发异常。想理解消息release和drain的不同,可以看“Garbage Collection。“一个autorelease pool应该总是在”其被创建的上下文”(比如一个方法或函数调用中,或者一个循环中)中被销毁。

使用Local AutoreleasePools降低内存峰值

很多程序创建自动释放的临时变量。这些变量放置在程序的内存中直到pool被销毁。你可以使用local autorelease pools帮助降低内存峰值。当你的pool销毁的时候,这些临时对象被释放,从而降低程序的内存峰值。

下面的例子展示一个循环中使用localautorelease pool的一个方法

NSArray *urls = <# An array of file URLs #>;

for (NSURL *urlin urls)  {

NSAutoreleasePool *loopPool = [[NSAutoreleasePoolalloc]init];

NSError *error =nil;

NSString *fileContents = [[[NSStringalloc]initWithContentsOfURL:url

encoding:NSUTF8StringEncodingerror:&error]autorelease];

/* Process the string, creating and autoreleasing more objects. */

[loopPool drain];

}

For循环一次处理一个文件。一个NSAutoreleasePool对象在循环的开始被创建,在循环的末尾被销毁。因此,这个循环中任何一个发送autorelease消息的对象都会被放到这个loopPool中,当loopPool在循环的最后被销毁时这些对象被释放。

一个autorelease pool被销毁后,你应该认为这个pool被销毁前存放的autoreleased对象都被销毁掉了。不要再向之前在pool中的对象发送消息或把它返回给你的方法的调用者。如果你必须在一个autorelease上下文之外使用一个临时对象,可以像下面的例子描述的那样,在这个上下文中向这个对象发送一个retain消息,然后在这个pool被销毁后向这个对象发送一个autorelease消息。

– (id)findMatchingObject:(id)anObject {

id match = nil;

while (match == nil) {

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

/* Do a search that creates a lot of temporary objects. */

match = [self expensiveSearchForObject:anObject];

if (match != nil) {

[match retain]; /* Keep match around. */

}

[subPool drain];

}

return [match autorelease];   /* Let match go and return it. */

}

在subpool起作用的时候,向match发送一个retain消息,在subpool销毁后,向它发送一个autorelease消息,通过这样,match从subpool转移到subpool之前起作用的pool中。这样扩展了match的生命周期并且使它可以在循环外接收消息、返回给findMatchingObject:的调用者。

AutoreleasePools和线程

在Cocoa应用程序中,每个线程管理它自己的NSAutoreleasePool的栈。当一个线程终止时,它自动的释放所有与它关联的autorelease pool。如果你写一个只使用Foudation框架的应用或者你自己创建一个线程时,你需要创建自己的autorelease pool。

如果你的应用或线程生命周期很长并且可能会生成很多自动释放的对象,那么你应该周期的销毁和创建autorelease pool(就像Kit框架在主线程开始所做的那样)。

否则的话,自动释放的对象会堆积,你的应用的内存峰值会增长。如果你自己创建的线程做Cocoa相关的调用,你就不需要创建autorelease pool。

注意:

如果你使用POSIX threadAPIs而不是使用NSThread创建一个线程,你就不能使用Cocoa,包括NSAutoreleasepool,除非Cocoa是在多线程模式。Cocoa 只有在创建它的第一个分离的线程对象后才会进入多线程模式。为了在随后创建的POSIX线程中使用Cocoa,你的应用必须首先创建一个分离的NSThread对象,并且这个分离的线程会马上退出。你可以使用NSThread的类方法isMultiThreaded测试Cocoa是否在多线程模式。

AutoreleasePools的作用域和嵌套的Autorelease Pools的实现

通常说autorelease pool是嵌套的,也可以认为嵌套的autoreleasepool是放在一个栈上,最内层的autorelease pool是放在栈顶。程序中的每个线程管理一个autorelease pools的栈。当你创建一个autorelease pool时,它被放到当前线程的autorelease pool的栈的顶端。当一个对象发送一个autorelease消息或者当它做为addObject的参数传递时,它总是被放在autorelease pool栈的顶端的aurelease pool中。

一个autorelease pool是否起作用与它在栈中的位置有关。栈顶端的pool是自动释放的对象被添加到的地方。如果一个新的pool被创建,那么当前最顶端的pool会变为不起作用的直到新创建的pool被销毁。(这样之前的pool又变为最顶端的pool)。当它被销毁的时候,它将永远不会再起作用。

如果你销毁一个非栈最顶端的autoreleasepool时,那么这个栈中所有在这个autorelease pool之上autorelease pool被销毁(会向它们中的所有对象发送release消息)。如果当你使用完一个autorelease pool而没有销毁它(一般不建议),这个pool会被销毁当它嵌套的autorelease pool被销毁的时候。

这个行为忽略掉了有异常的情况。如果一个异常发生了,线程突然退出当前上下文,这个pool关联的上下面文被销毁了。然而,如果那个pool不是位于线程栈最顶端的pool,那么这个pool上面的所有pool都会被销毁(这个过程会释放掉所有的对象)。这个pool下面的一个pool会成为栈顶autorelease pool。因为这样,所以异常处理不需要释放autorelease pool中的对象。对于异常处理没有必要也不值得向它的autorelease pool发送release消息,除非异常会重新触发这个异常。

Autorelease pools 官方文档的更多相关文章

  1. 【AutoMapper官方文档】DTO与Domin Model相互转换(上)

    写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...

  2. 2DToolkit官方文档中文版打地鼠教程(三):Sprite Collections 精灵集合

    这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...

  3. 2DToolkit官方文档中文版打地鼠教程(二):设置摄像机

    这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...

  4. 2DToolkit官方文档中文版打地鼠教程(一):初始设置

    这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...

  5. 【AutoMapper官方文档】DTO与Domin Model相互转换(中)

    写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...

  6. 【AutoMapper官方文档】DTO与Domin Model相互转换(下)

    写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...

  7. Ionic2系列——Ionic 2 Guide 官方文档中文版

    最近一直没更新博客,业余时间都在翻译Ionic2的文档.之前本来是想写一个入门,后来觉得干脆把官方文档翻译一下算了,因为官方文档就是最好的入门教程.后来越翻译越觉得这个事情确实比较费精力,不知道什么时 ...

  8. Kotlin开发语言文档(官方文档)-- 目录

    开始阅读Kotlin官方文档.先上文档目录.有些内容还未阅读,有些目录标目翻译还需琢磨琢磨.后续再将具体内容的链接逐步加上. 文档链接:https://kotlinlang.org/docs/kotl ...

  9. 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍

    我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...

随机推荐

  1. bzoj3995

    线段树 额 计蒜客竟然把这个出成noip模拟题... 这个东西很像1018,只不过维护的东西不太一样 然后我参考了fuxey大神的代码,盗一波图 具体有这五种情况,合并请看代码,自己写了一个结果wa了 ...

  2. Github个人主页不显示提交记录的问题

    最近发现自己连续三天在github上的提交没显示在个人主页上,一番搜索后终于发现原来是因为没有把git的配置改过来,提交的代码时使用了不同的email. https://code.bradymower ...

  3. vs2008添加消息函数方法

    开发MFC时,开发工具VS2008不能像开发工具VC++6.0那样,直接在类文件上右击选择“Add Window Message Handles”来添加消息映射.对于我这个初学者,刚开始一直没找到可以 ...

  4. 运用NP求解 “跳跃游戏”---计蒜客

    计蒜客里面有一道“跳跃游戏的问题” 给定一个非负整数数组,假定你的初始位置为数组第一个下标. 数组中的每个元素代表你在那个位置能够跳跃的最大长度. 你的目标是到达最后一个下标,并且使用最少的跳跃次数. ...

  5. Java SE 第二篇

    二.  Java SE 第二篇 1.  Arrays 数组 // 声明一维数组,[]内不允许有值 int[] arr; int arr[]; // 创建一维数组对象,[]内必须有值 arr = new ...

  6. _bzoj1009 [HNOI2008]GT考试【矩阵加速dp】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1009 比较不错的一道题,令f(i, j)表示考号匹配到i位,后j位为不吉利串的前j位,那么对 ...

  7. 题解报告:NYOJ #311完全背包(恰好装满)

    描述: 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是w.求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题 ...

  8. JD商家后台管理的细节

    1: 宝贝主图和滚动图都是800px,只有刚好这么多时才能得到显示,否则不会显示. 2:宝贝描述图只支持750px, 只有这么多时才能得到显示, 刚开始不知道, 上传图片上去后, 发现始终无法显示, ...

  9. shell 调试 2例

    1.############# #!/bin/ksh if [ ! -z $TNS_ADMIN ]; then      export TNS_ADMIN=`dirname $TNS_ADMIN`   ...

  10. hdu 6012 Lotus and Horticulture 打标记

    http://acm.hdu.edu.cn/showproblem.php?pid=6012 我们希望能够快速算出,对于每一个温度,都能够算出它在这n颗植物中,能得到多少价值. 那么,对于第i科植物, ...