【问题标题】:ARC: Memory does not get reclaimed?ARC:内存没有被回收?
【发布时间】:2012-03-12 11:49:24
【问题描述】:

我正在开发一个 iPad(仅限)应用程序,但我偶然发现了一个奇怪的问题。该应用程序在 iPad 1 上出现内存警告后终止,但在 iPad 2 上运行良好。 我正在使用 ARC 并以 iOS 5 为目标。我使用笔尖,我的大部分资产都是使用 UIImageViews 显示的。我还有几百个按钮和大量手势识别器……我在 ARC 上重新观看了 WWDC11 视频(第 323 和 322 节),我似乎没有做任何特别的事情。

该应用程序是 UIImage 密集型应用程序,我正在使用 UIImage 制作大量动画。但是,我使用的是 initWithContentsOfFile 构造函数而不是 imageNamed 调用。我正在尝试防止图像被系统缓存。

我还使用 GCD 来安排声音效果和动画视图。我总是在主线程上这样做。

应用程序使用 UINavigationController,它的堆栈上永远不会有超过 1 个 UIViewController。我可以确认这是真的,因为 didReceiveMemoryWarning 只在当前视图控制器上被调用(我正在记录调用)。

我不明白的是,为什么 Instruments 在 Allocations 和 VM Tracker 工具中都报告了很高的数字(好像视图控制器没有被释放)。当我从一个视图控制器导航到另一个视图控制器时,Allocations 工具显示了一个小下降(这是我所期望的),但 VM Tracker Instrument 显示当我做同样的事情时脏大小没有下降。最终,该应用程序使用了太多内存并被终止(在 iPad 1 上)。当我在 iPad 2 上收到内存警告时,应用程序并没有终止...

感觉好像我的图像、声音或视图没有被破坏,内存也没有被回收......我的对象层次结构非常基本,不应该有任何类型的保留循环。我什至没有简单的代表...

你有什么建议吗?我真的不想只为 iPad 2 或更新版本发布这个应用程序......这是一个为孩子们准备的应用程序,这将是一个遗憾......我会很高兴得知我做错了什么,因为我真的想确保这个应用程序是最好的......

干杯, 尼克

【问题讨论】:

  • 简短评论:我花了很多时间使用仪器寻找泄漏,但看起来没有。另外,如果有的话,我认为 iPad 2 最终会崩溃并烧毁,但它不会......

标签: objective-c ios ipad memory automatic-ref-counting


【解决方案1】:

我不喜欢回答我自己的问题,但我认为这可能对未来的谷歌员工有所帮助。我实现了自己的基于 UIImage 的动画,并且不再使用 animationImages 属性。事实证明,我的内存问题现在已经消失了,因为我不再需要将所有图像存储在内存中,而是使用计时器根据需要加载它们。

我实际上认为推出自定义动画是有益的,因为它允许回调和更强大的自定义选项。

一旦我对它感到满意并且我觉得它已经准备好分享了,我会将课程发布到 GitHub 上。

【讨论】:

    【解决方案2】:

    有一些方法可以说,当某些东西不需要时,通过将它们的属性设置为 nil 来“优化”你的对象——所以虽然你不能再编写 dealloc 方法,但你可以做 @987654324 @(当相关时)最终在非 ARC 世界中为“保留”(即strong)属性做类似的事情:

    - (void)setObject:(id)newObject
    {
       [object release]; // send release message to current object
       object = newObject; // set reference to newObject
       [object retain]; // send retain message to newObject
    }
    

    现在,在 ARC 中,您不能/不能在代码中自己编写保留/释放,编译器会为您插入这些调用,这意味着实际上,将属性设置为 nil 会在上面执行此操作示例:

    [object release]; // send release message to current object
    object = nil; // set reference to nil
    [object retain]; // send retain message to nil (no effect)
    

    此外,这只是冰山一角——您应该确保您的代码中有no retain cycles,这可能会导致对象泄漏而无法对其进行破坏。这意味着,当您应该使用 weak 属性时,您可能会在某些地方使用 strong 对属性(即对象)的引用。不同之处在于,强引用是retained,而weak 引用是assigned,前者的retainCount 递增,而后者的属性赋值是手写的,如下所示:

    - (void)setObject:(id)newObject
    {
       object = newObject;
    }
    

    【讨论】:

    • 你可以编写dealloc方法——你不能在任何东西上调用release,也不能调用[super dealloc]。但是dealloc 的清理方法仍然是洁净的。
    • 谢谢 Alan,我将 viewDidDisappear 和 viewDidUnload 中的所有内容都设置为 nil。确实调用了 dealloc,但对实际内存占用没有影响。鉴于项目的扁平结构应该没有保留周期,但我会再检查一次......
    • @Steve 我实际上已经编写了自己的 dealloc,只是为了查看它何时被调用。它确实会在预期的时候被调用......
    • @Steve 它不是 KVC 使用 dealloc 作为说 self.object = nil 的地方。
    • @AlanZeino - 我不认为它曾经是 - 是吗?我坚持使用viewDidUnload 中的self.retainedSubviewProperty = nil,但始终使用dealloc 中的[retainedSubviewProperty release]
    猜你喜欢
    • 2013-12-15
    • 1970-01-01
    • 2011-10-16
    • 2012-02-25
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 2010-12-15
    相关资源
    最近更新 更多