Autorelease pools 官方文档
翻译自:
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 官方文档的更多相关文章
- 【AutoMapper官方文档】DTO与Domin Model相互转换(上)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- 2DToolkit官方文档中文版打地鼠教程(三):Sprite Collections 精灵集合
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
- 2DToolkit官方文档中文版打地鼠教程(二):设置摄像机
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
- 2DToolkit官方文档中文版打地鼠教程(一):初始设置
这是2DToolkit官方文档中 Whack a Mole 打地鼠教程的译文,为了减少文中过多重复操作的翻译,以及一些无必要的句子,这里我假设你有Unity的基础知识(例如了解如何新建Sprite等) ...
- 【AutoMapper官方文档】DTO与Domin Model相互转换(中)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- 【AutoMapper官方文档】DTO与Domin Model相互转换(下)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- Ionic2系列——Ionic 2 Guide 官方文档中文版
最近一直没更新博客,业余时间都在翻译Ionic2的文档.之前本来是想写一个入门,后来觉得干脆把官方文档翻译一下算了,因为官方文档就是最好的入门教程.后来越翻译越觉得这个事情确实比较费精力,不知道什么时 ...
- Kotlin开发语言文档(官方文档)-- 目录
开始阅读Kotlin官方文档.先上文档目录.有些内容还未阅读,有些目录标目翻译还需琢磨琢磨.后续再将具体内容的链接逐步加上. 文档链接:https://kotlinlang.org/docs/kotl ...
- 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍
我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...
随机推荐
- MySQL基础操作——转
原文: [培训]MySQL yum安装mysql:yum -y install mysql*- 或者 yum -y install mysql* 启动数据库服务:/etc/init.d/mysqld ...
- bzoj 4080: [Wf2014]Sensor Network【瞎搞+随机化】
参考:https://blog.csdn.net/YihAN_Z/article/details/73380387 一点都不想写正解.jpg random_shuffle一下然后贪心的加点,和ans取 ...
- P4148 简单题(KDTree)
传送门 KDTree 修改权值当做插入节点,不平衡就暴力重构,询问的时候判断当前节点代表的矩形是否在询问的矩形的,是的话返回答案,相离返回0,否则的话判断当前点是否在矩形内,然后继续递归下去 //mi ...
- centos 7更换阿里源
转自 https://blog.csdn.net/jameshadoop/article/details/54881295 centos7 修改yum源为阿里源,某下网络下速度比较快 首先是到yum源 ...
- 【SpringCloud构建微服务系列】学习断路器Hystrix
一.Hystrix简介 在微服务架构中经常包括多个服务层,比如A为B提供服务,B为C和D提供服务,如果A出故障了就会导致B也不可用,最终导致C和D也不可用,这就形成了雪崩效应. 所以为了应对这种情况, ...
- header的参数不能带下划线
移动端把一些公共参数放在了 header 了, 在 laravel 中使用 use \Illuminate\Http\Request; //这个是获取所有header信息Request::header ...
- Robot Framework问题汇总...不断更新中
在实际使用Robot Framework工具过程中,难免会遇到一些问题, 我们将会一一记录下来,以便后来者碰到类似的问题能够快速解决! 安装类问题: ========================= ...
- openssh安装、设置指定端口号、免密码登录、变量传递、防暴力破解
首先确保机器挂在好光盘镜像,然后查看软件包信息 [root@xuegod63 ~]# df -hFilesystem Size Used Avail Use% Mounted on/dev ...
- js 常用处理
判断浏览器环境是PC端还是手机端 function goPAGE() { if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios| ...
- "CSRF token missing or incorrect."的解决方法.
现象: Forbidden (403)CSRF verification failed. Request aborted.HelpReason given for failure:CSRF token ...