翻译自:

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. 字符设备驱动另一种写法—mmap方法操作LED

    最近在看韦老师的视频,讲解了很多种字符设备的驱动写法.经过自己的研究之后,我发现还有另外一种写法,直接在应用层操作,省去了内核中的地址映射部分,使得用户可以在应用层直接操作LED.        mm ...

  2. WebUploader上传大文件时,上传出错问题

    上传普通文件没有问题,当文件达到一定大小的时候,上传错误,返回结果是404,我可以肯定的是路径是没有问题的.因为上传小文件等都是可以的. 然后使用webuploader的uploaderror监控错误 ...

  3. 在 SharePoint 2013 中针对地理位置字段创建地图视图

    在 SharePoint 2013 中针对地理位置字段创建地图视图 了解如何通过在 SharePoint 2013 列表中使用地图视图来显示位置信息.您可以通过 SharePoint 用户界面 (UI ...

  4. PHP编程常见小错误错误

    使用PHP的过程中经常因为粗心出一些简单的错误,先将自己遇到几个的记录下来,以后慢慢增加. 1 Fatal error: Function name must be a string 翻译很简单,就是 ...

  5. ==和equals()的不同点

    两者都可以用于对象的比较."=="用于比较两个对象的内存地址值(引用值)是否相等,equals()方法用于比较两个对象的内容是否一致. String str1 = new Stri ...

  6. Gym 100962J Jimi Hendrix (树形DP)

    题意:给定一棵树,然后每条边有一个字母,然后给定一行字符串,问你能不能从这棵树上找到,并输出两个端点. 析:树形DP,先进行递归到叶子结点,然后再回溯,在回溯的时候要四个值,一个是正着匹配的长度和端点 ...

  7. ASP.NET Core MVC 打造一个简单的图书馆管理系统 (修正版)(五)外借/阅览图书信息的增删改查

    前言: 本系列文章主要为我之前所学知识的一次微小的实践,以我学校图书馆管理系统为雏形所作. 本系列文章主要参考资料: 微软文档:https://docs.microsoft.com/zh-cn/asp ...

  8. 进击的Python【第十六章】:Web前端基础之jQuery

    进击的Python[第十六章]:Web前端基础之jQuery 一.什么是 jQuery ? jQuery是一个JavaScript函数库. jQuery是一个轻量级的"写的少,做的多&quo ...

  9. iOS开发之邮件发送代码

    邮件发送功能是由MessageUI Framework提供的,这个框架是iPhone sdk中最简单的框.由一个类.一个视图控制器,一个protocol组成. 一.创建视图控制器: MFMailCom ...

  10. iOS- NSThread/NSOperation/GCD 三种多线程技术的对比及实现 -- 转

    1.iOS的三种多线程技术 1.NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) 2.以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题 ...