高级内存管理编程指南关于@autoreleasepool:
使用本地自动释放池块来减少峰值内存占用
许多程序创建自动释放的临时对象。这些对象添加到程序的内存占用空间,直到块在许多情况下,允许临时对象累积直到当前事件循环迭代结束时开销过大;但是,在某些情况下,您可能会创建大量临时对象,大量添加到内存中占地面积和您想要更快地处理的。在这些在后一种情况下,您可以创建自己的自动释放池块。在块结束时,临时对象被释放,通常导致它们的释放,从而减少程序的内存脚印
以下示例显示如何使用本地自动释放池for循环中的块。
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
@autoreleasepool {
NSError *error;
NSString *fileContents = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
}
}
这个代码也可以在没有自动释放池的情况下编写并有效管理吗?
比如创建一个property of fileContents
并在处理后将其设置为nil
self.filecontents = nil;
问题是stringWithContentsOfURL
可以返回一个自动释放的对象。但是你可以使用改为initWithContentsOfURL
:
NSArray *urls = <# An array of file URLs #>;
for (NSURL *url in urls) {
NSError *error;
NSString *fileContents = [[NSString alloc] initWithContentsOfURL:url
encoding:NSUTF8StringEncoding error:&error];
/* Process the string ... */
fileContents = nil;
}
init...
方法返回一个(+1)保留的对象,而不是一个自动释放的对象,因此fileContents = nil
释放对象并销毁它(如果没有其他对它的强烈引用)。
当然,只有当"字符串处理代码"不产生其他自动释放的对象。(此外,如果设置了error
,则会自动释放对象。)
(实际上并不能"保证"stringWithContentsOfURL
返回自动释放对象特别是在发布模式下,ARC编译器消除了许多不必要的保留/自动释放/释放操作。)
我不知道建立一个本地自动释放池是否是一项昂贵的操作(我想不会)。如果您在循环中处理许多对象,但您不知道无论是否创建了自动释放的对象,都可能是明智的只需使用本地自动释放池并"不关心它"。使用"仪器"进行分析也可以提供更多的见解。
有关详细信息,请参阅"保留的返回值"one_answers"未保留的返回数值"Clang ARC文档中。
分配给强属性然后将其清零,分配给强局部变量并使其超出范围没有区别。根本问题是,分配给fileContents
的对象被放置在自动释放池中,至少在for
循环完成迭代所有URL之前,该池不会被耗尽。将循环体放在@autoreleasepool
块中会导致每次循环迭代都自动释放fileContents
。
表面上看起来是这样,但您进行的任何可可方法调用都可能在幕后创建一个自动释放的对象。。。正如您所看到的,如果您在没有自动释放池的情况下对另一个线程执行同类操作。
如果您有长时间运行的循环,那么添加一个单独的池是明智的。
还有一种曾经更受欢迎的模型,它是这样的:
NSAutoreleasePool * pool = [NSAutoreleasePool new];
for (int i =0;i>3009;i++){
//do stuff;
if(!(i%100))
{
[pool drain],pool = [NSAutoreleasePool new];}
}
[pool drain];