【问题标题】:Why is autorelease especially dangerous/expensive for iPhone applications?为什么自动释放对 iPhone 应用程序特别危险/昂贵?
【发布时间】:2010-10-11 10:41:21
【问题描述】:

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

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

SO 参考资料:
autorelease-iphone
Why does this create a memory leak (iPhone)?

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

真实的故事是什么?

【问题讨论】:

    标签: iphone objective-c performance autorelease


    【解决方案1】:

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

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

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

    不过,这建议谨慎使用自动释放,而不是完全避免。

    (现在是我的评论)

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

    【讨论】:

    • 乐于助人(给了我一些东西可以搜索:-)
    • 他们没有提到的是 Foundation 中的许多类在它们管理的对象上调用 autorelease,因此在紧密的循环中,如果您正在处理即使是适度的,您也需要创建和管理自己的自动释放池数据量。
    • 我认为维护池不是开销;相反,在内存受限的环境中,最好不要分配内存但不要使用超过必要的时间。自动释放使内存分配的时间超过了必要的时间。
    • @Paul,是的,我昨晚在回家的路上想到了这个……然后我猜我忘了更新我的答案——很好。
    • 文档 DO NOT SAY 避免使用-autorelease,他们说要避免使用NSAutoreleasePool。 (看到“autorelease”后面的“pools”这个词吗?)原因是当你在受限环境中对大量数据进行大型操作时,使用-release 更好,因为你可以更明确地控制对象,从而为您的剩余操作释放更多资源。 autorelease 的开销非常小(如果 NeXT 盒子能在 20 年前处理它,那么 iPhone 也能)
    【解决方案2】:

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

    要回答这个问题,您应该首先了解什么是自动释放的正确用途。假设您有一个具有两个属性的类: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,因此如果您不想泄漏,调用者应该在完成后释放它。从调用者的角度来看,他只是请求了一个属性值fullName。他不知道他得到了一个在使用后应该释放的全新对象,而不是对类内部持有的 NSString 的一些引用!

    如果我们把[str release]放在return之前,字符串会被销毁,方法会返回垃圾!这就是我们使用[str autorelease] 标记对象以便稍后释放的地方(通常是在事件处理完成时)。这样调用者就得到了他的对象,而不必担心他是否应该释放它。

    惯例是在方法将新对象返回给调用者之前对新对象调用 autorelease。例外是名称以allocnewcopy 开头的方法。在这种情况下,调用者知道为他们创建了一个全新的对象,他们有责任在该对象上调用 release。

    完全用 autorelease 代替 release 是个坏主意,因为对象会很快堆积并阻塞内存,尤其是在循环中。 iPhone 上的资源是有限的,因此为了尽量减少内存占用,您有责任在使用完对象后立即释放它。

    【讨论】:

      【解决方案3】:

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

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

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

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

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • -1。你当然可以说它的效率有点低,但自动释放不会产生错误。如果您遵循内存管理规则(包括自动释放),则不会出现内存错误。不守规矩,手动放东西救不了你。
          猜你喜欢
          • 2011-01-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-13
          • 2011-06-18
          • 2015-03-08
          • 2017-10-12
          • 1970-01-01
          相关资源
          最近更新 更多