14

我正在寻找一个主要来源(或一个非常好的解释)来支持在autorelease为 iPhone 编写软件时使用是危险的或过于昂贵的说法。

有几位开发人员提出了这种说法,我什至听说苹果不推荐它,但我无法找到任何具体的来源来支持它。

SO 参考:
autorelease-iphone
为什么这会造成内存泄漏(iPhone)?

注意:我可以看到,从概念的角度来看,这autorelease比简单地调用 稍微贵一些release,但我认为小惩罚不足以让 Apple 推荐反对它。

真实的故事是什么?

4

5 回答 5

11

(不能接受你自己的答案?)

好吧,毕竟,我确实设法找到了来自 Apple Developer 的参考资料,在页面底部附近作为旁注添加:

iPhone OS 注意:因为在 iPhone OS 上,应用程序在更受内存限制的环境中执行,所以不鼓励在应用程序创建许多对象的方法或代码块(例如循环)中使用自动释放池。相反,您应该尽可能显式释放对象。

尽管如此,这仍然建议谨慎使用自动释放,而不是完全避免它。

(现在我的评论)

听起来维护池有一定的开销。我读了这篇文章,这可能会导致我尽可能避免自动释放,因为我更喜欢保持一致。如果您在自动释放下有一些内存,而其他内存完全是手动管理的,则可能会更加混乱。

于 2009-03-05T05:36:11.527 回答
9

使用或不使用 autorelease 不是问题,因为在某些情况下,autorelease 是您通过的唯一方法。问题应该是“为什么不对所有对象使用自动释放,而不是使用保留和释放? ”。

要回答这个问题,您应该首先了解什么是自动释放的正确用途。假设您有一个具有两个属性的类:firstName 和 lastName。每个都有一个 getter 和一个 setter。但是您还需要一个返回 fullName 的方法,将这两个字符串连接成一个全新的字符串:

- (NSString *) fullName {
   NSString str = [[NSString alloc]initWithFormat:@"%@ %@", firstName, lastName];
   // this is not good until we put [str autorelease];
   return str;
}

那张图有什么问题?返回字符串的引用计数为 1,因此如果您不想泄漏,调用者应该在完成后释放它。从调用者的角度来看,他只是请求了一个属性 value fullName。他不知道他得到了一个在使用后应该释放的全新对象,而不是对类内部持有的 NSString 的一些引用!

If we put the [str release] before return, the string would be destroyed and the method would return garbage! That's where we use [str autorelease], to mark the object for release at a later time (typically when the event processing is done). That way the caller gets his object, and does not have to worry whether he should release it or not.

The convention is to call autorelease on a new object before the method returns it to the caller. Exceptions are methods with names that start with alloc, new or copy. In such cases the callers know that a brand new object is created for them and it is their duty to call release on that object.

Replacing release with autorelease altogether is a bad idea, since the objects would pile up and clog the memory very quickly, especially in loops. The resources on the iPhone are limited, so in order to minimize memory hogging, it is your duty to release the object as soon as you're done with it.

于 2011-01-06T20:51:21.360 回答
5

我不同意完全避免自动释放是明智的。

Cocoa Touch 在内部非常频繁地使用它,并且在许多情况下,它是正确分配内存的唯一方法(一个很好的例子是可重用的表格视图单元格)。如果您了解正在发生的事情,那么自动释放池是您可以使用的一个很好的工具。要记住的主要事情是,直到运行循环中的某个时间点才释放块。如果你在没有用户交互的情况下运行一个紧密的循环并且正在堆积自动释放块,你最终会耗尽内存。

Autorelease 不能替代垃圾收集(iPhone SDK 中不可用),并且可能导致令人讨厌的悬空指针错误(指针似乎仍然很好,然后在某些不可预测的点变得无效),但在编写时也非常有用清晰且易于维护的代码。考虑以下情况:

[aDictionary writeToFile:
     [documentsDirectory stringByAppendingPathComponent:@"settings.plist"]
              atomically:YES];

路径字符串作为自动释放对象生成。我们不需要创建临时对象,因此我们避免了这种开销(以及我们可能忘记释放它的可能性)。内存将被完全释放(没有泄漏),只是它会在运行循环的后期发生。问问自己:在我回到用户输入之前,我会分配数百个这些吗?如果没有(就像这里的情况一样),自动释放是一个很好的解决方案,实际上这种用于处理路径的 NSString 方法只能使用自动释放的内存。

我同意上面的海报,即遵循惯例并保持一致是一个非常好的主意。

于 2009-03-05T20:36:48.417 回答
4

我倾向于尽可能避免在 iPhone 上使用自动释放(正如 Jon 指出的那样,你不能总是没有它),仅仅是因为我想知道我正在使用的对象会在我不释放的那一刻被释放需要他们。内存限制是您在设备上将面临的最大问题之一,我相信它们是您在那里发现的大多数崩溃问题的根源。

正如 Apple 所强调的,当您在任何类型的循环中使用自动释放的对象时,需要特别关注的一个方面,因为它们会堆积在自动释放池中。然后,您必须管理何时耗尽池或创建/释放池。每次通过循环都这样做可能会降低性能,但是如果没有通过太多次可能会导致危险的内存使用。我仍在 Molecules 中对此进行调整,因为从蛋白质数据库导入大型 (>2 MB) 文本文件时会出现间歇性内存问题。我能够通过最小化自动释放的对象来提高性能,但不能完全消除它们。

另一个需要注意的领域是使用带有线程的自动释放对象。如果可能,在处理在后台线程上执行的方法时不要使用自动释放的对象,因为池可能会在随机时间耗尽。这会导致间歇性崩溃,追踪起来真的很有趣。

于 2009-03-05T22:19:12.413 回答
0

我强烈建议避免像瘟疫一样自动释放。内存管理错误是浪费大量时间和金钱的好方法,我有幸在旧的 Mac 应用程序上多次经历这个过程,而 iPhone 的内存限制很严格意味着你有要非常小心,否则应用程序将不稳定并经常崩溃……就像去年夏天发布的许多第一批应用程序一样。

我发现编写稳定的 iPhone 应用程序的唯一可靠方法是自己管理所有内存,并且始终如一地执行此操作。即使您是项目中唯一的程序员,您也会在以后感谢自己。如果你学会了用“为你处理一切”的语言编程可能会很困难,但如果你认真地想创建高质量的 iPhone 应用程序,那么学习如何做得好确实是值得的。

于 2009-03-05T06:16:29.747 回答