博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高级内存管理编程指南-使用自动释放池块
阅读量:3594 次
发布时间:2019-05-20

本文共 2295 字,大约阅读时间需要 7 分钟。

使用自动释放池块

自动释放池块提供了一种机制,您可以放弃对象的所有权,但避免立即释放它(例如从方法返回对象时)。通常,您不需要创建自己的自动释放池块,但在某些情况下,您必须或者这样做是有益的。

关于 Autorelease Pool Blocks

使用标记自动释放池块@autoreleasepool,如以下示例所示:

@autoreleasepool {
//创建自动释放对象的代码。
}

在自动释放池块的末尾,在块中接收到autorelease 消息release的对象被发送消息 - 对象release在每次在块内发送消息时接收消息autorelease

与任何其他代码块一样,自动释放池块可以嵌套:

@autoreleasepool {
// 。。
@autoreleasepool {
// 。。
}
。。。
}

(您通常不会完全按上述方式查看代码;通常,一个源文件中的自动释放池块中的代码将调用另一个自动释放池块中包含的另一个源文件中的代码。)对于给定的autorelease消息,将release发送相应的消息在autorelease发送消息的自动释放池块的末尾。

Cocoa 总是希望代码在自动释放池块中执行,否则自动释放的对象不会被释放而应用程序会泄漏内存。(如果您autorelease在自动释放池块之外发送消息,Cocoa 会记录一个合适的错误消息。)AppKit 和 UIKit 框架处理自动释放池块中的每个事件循环迭代(例如鼠标按下事件或轻击)。因此,您通常不必自己创建自动释放池块,甚至不必查看用于创建池的代码。但是,有三种情况可能会使用您自己的自动释放池块:

  • 如果您正在编写不基于 UI 框架的程序,例如命令行工具。

  • 如果编写一个创建许多临时对象的循环。

    您可以在循环内使用自动释放池块在下一次迭代之前处理这些对象。在循环中使用自动释放池块有助于减少应用程序的最大内存占用量。

  • 如果你产生一个辅助线程。

    一旦线程开始执行,您必须创建自己的自动释放池块;否则,您的应用程序将泄漏对象。(有关详细信息,请参阅。)

使用本地自动释放池块来减少峰值内存占用量

许多程序创建自动释放的临时对象。这些对象会添加到程序的内存占用空间,直到块结束。在许多情况下,允许临时对象累积直到当前事件循环迭代结束时不会导致过多的开销;但是,在某些情况下,您可能会创建大量临时对象,这些对象会大大增加内存占用,并且您希望更快地处置。在后面这些情况下,您可以创建自己的自动释放池块。在块结束时,临时对象被释放,这通常导致它们的释放,从而减少程序的内存占用。

以下示例显示了如何在for循环中使用本地自动释放池块。

NSArray * urls = <#一个文件URL数组#>;
for(NSURL * url in urls){
 
@autoreleasepool {
NSError *错误;
NSString * fileContents = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
/ *处理字符串,创建和自动释放更多对象。* /
}
}

for循环一次处理一个文件。在块结束时释放在自动释放池块内fileContents发送autorelease消息的任何对象(例如)。

在自动释放池块之后,您应该将块中自动释放的任何对象视为 “已处置”。不要向该对象发送消息或将其返回给您的方法的调用者。如果必须使用自动释放池块之外的临时对象,则可以通过向retain块内的对象发送消息然后在块之后发送它autorelease来执行此操作,如以下示例所示:

- (id)findMatchingObject:(id)anObject {
 
id匹配;
while(match == nil){
@autoreleasepool {
 
/ *执行创建大量临时对象的搜索。* /
match = [self expensiveSearchForObject:anObject];
 
if(match!= nil){
[匹配保留]; / *保持匹配。* /
}
}
}
 
return [match autorelease]; / *让匹配去并返回它。* /
}

发送retainmatch自动释放池块并autorelease在自动释放池块之后发送到它并延长其生命周期match并允许它在循环外接收消息并返回给调用者findMatchingObject:

自动释放池块和线程

Cocoa 应用程序中的每个线程都维护自己的自动释放池块堆栈。如果您正在编写仅基于 Foundation 的程序或者分离线程,则需要创建自己的自动释放池块。

如果您的应用程序或线程长寿并且可能生成大量自动释放的对象,则应使用自动释放池块(如主线程上的 AppKit 和 UIKit); 否则,自动释放的对象会累积,并且您的内存占用会增加。如果您的分离线程没有进行 Cocoa 调用,则不需要使用自动释放池块。

注意:  如果使用 POSIX 线程 API 而不是创建辅助线程NSThread,除非 Cocoa 处于多线程模式,否则不能使用 Cocoa。Cocoa 仅在分离其第一个NSThread对象后才进入多线程模式。要在辅助 POSIX 线程上使用 Cocoa,您的应用程序必须首先分离至少一个NSThread可以立即退出的对象。您可以使用NSThread类方法测试 Cocoa 是否处于多线程模式

转载地址:http://qqhwn.baihongyu.com/

你可能感兴趣的文章
centos7安装docker
查看>>
centos7搭建svn
查看>>
TortoiseSVN无法查看日志
查看>>
centos7设置svn开机自启
查看>>
nginx负载均衡配置
查看>>
idea将普通java代码打成jar包
查看>>
java快速读取大数据量的Excel文件,格式为.xlsx
查看>>
将普通maven工程中某一接口改造成dubbo服务
查看>>
k8s集群中其他节点也可以执行kubectl命令
查看>>
使用docker制作tomcat镜像
查看>>
shell脚本读取文件内容,并写出新文件
查看>>
在docker宿主机上运行docker中container中的执行的命令
查看>>
nginx和tomcat的ssl认证使用https协议访问
查看>>
docker使用tomcat部署应用
查看>>
linux服务器之间复制文件
查看>>
k8s集群搭建
查看>>
自己的阿里云镜像加速器查找
查看>>
spring-cloud-eureka初体验
查看>>
spring-cloud-ribbon简单使用
查看>>
spring-cloud-feign的简单使用
查看>>