【问题标题】:Why does iOS terminate my app even when I free lots of memory in response to memory warnings?为什么即使我释放大量内存以响应内存警告,iOS 也会终止我的应用程序?
【发布时间】:2012-01-20 13:38:13
【问题描述】:

即使在我释放大量内存以响应内存不足警告之后,我也无法弄清楚为什么 iOS 会由于内存使用而终止我的应用程序(iPad、iOS 4)。例如,这是一个典型的终止场景,我经常记录内存使用情况——查看“app”使用情况,即每行的第一个 KB 值:

...
2011-12-14 13:25:42.343 Oyster[211:707] Memory usage (KB): app 268256, delta 6472, used 366800/373940
2011-12-14 13:25:43.292 Oyster[211:707] Memory usage (KB): app 273900, delta 5644, used 372444/381024
2011-12-14 13:25:44.159 Oyster[211:707] Memory usage (KB): app 282920, delta 9020, used 381464/389116
2011-12-14 13:25:45.184 Oyster[211:707] Memory usage (KB): app 272140, delta -10780, used 370684/379432
2011-12-14 13:25:46.109 Oyster[211:707] Memory usage (KB): app 260412, delta -11728, used 358956/365900
2011-12-14 13:25:48.443 Oyster[211:707] Received memory warning. Level=2
2011-12-14 13:25:48.454 Oyster[211:707] Memory usage (KB): app 9172, delta -251240, used 107716/112548
(gdb)

您可以看到应用内存使用量不断增加,直到收到内存警告。然后我正确响应内存警告并释放一堆(250MB!)内存。那时我的应用程序被终止,iOS 进入 iPad 主屏幕。

此处的“内存使用”日志与我的 logMemoryUsage() function 一起显示,它基于来自 this answer 的代码。

作为记录,我使用SDWebImage 将 UIImages 缓存在内存中,但如图所示,它通过清空其缓存(此时相当大)来处理内存警告。我意识到我可以调整 SDWebImage 的缓存以不填满所有可用内存并等待内存警告,但这引出了以下问题......

为什么 iOS 会终止我的应用程序,即使我通过愉快地释放大量内存来响应内存警告?

【问题讨论】:

  • 请包含终止日志。其他地方可能存在不相关的错误。
  • 什么是“终止日志”,如何查看?
  • 开启调试器。当应用程序崩溃时,控制台应该有一条类似“App terminating due to...”的消息
  • 我在 Xcode 调试器中。 “(gdb)”之后根本没有任何消息——那是最后一个控制台日志。还有什么我需要启用的吗?
  • 在仪器中使用分配,模拟内存警告,检查内存是否确实被释放...

标签: objective-c ios memory-management terminate sdwebimage


【解决方案1】:

这是对内存管理等良好实践的一般答案。通常,听起来内存缓存变得太大了,即使它释放对象以响应内存警告,到那时它也是迟到了。

  1. 内存警告本身并不是“坏事”,您无法避免它们。它们是 iOS 生命周期的正常部分,您必须通过释放所有对象中的所有非必要数据来正确处理它们,以确保您的应用以负责任的方式运行。即使您的应用程序占用空间很小,您仍然可能会收到有关设备上其他条件的内存警告 b/c(例如正在使用的其他应用程序等)。我在这里指的是运行时通知UIApplicationDidReceiveMemoryWarningNotification。调试器消息(例如“收到内存警告。Level=2”)是特定于您的应用的,尽管它们不一定与接收运行时通知相关。

  2. 我对@9​​87654322@ 了解不多。我会查看实现并确保它有效地释放内存。例如,在相关位置使用@autoreleasepool 可能有助于它在运行循环中更有效地释放对象。

  3. 您应该努力使应用程序的内存占用尽可能受到限制。对图像数据使用内存缓存很好,但我会限制它的大小。如果您的应用程序的占用空间大于 250MB,即使您处理内存警告,它也会被终止,我并不感到惊讶。到那时可能为时已晚。

  4. 您可能有其他问题导致/促成终止。正如 cmets 所建议的,您需要在仪器中进行更多调试以查找泄漏、错误访问等。在此处发布崩溃日志会有所帮助。

【讨论】:

  • #3 +1。有时为时已晚。内存警告通过 IPC 传递,并且存在延迟。 250MB 很多。我愿意打赌“为时已晚”。
  • @ipmcc,出于兴趣,内存警告是通过 IPC 传递的事实记录在某处,还是您从公共源代码或其他原因知道这一点?
  • 您可以使用调试器(超出 SO 注释范围的详细信息)看到内存警告以 mach 消息(即 IPC)的形式到达,该消息会变成主线程调度操作,最终触发应用级通知。在我能找到的任何地方都没有记录详细信息。最重要的是,没关系。如果警告来自您的进程内部,那么它们对于来自您的进程外部的 kill 仍然是异步的。最终结果:无论如何它都是异步的,并且会有您无法控制/解释的延迟。
  • 值得注意的是,OpenGL 持有的内存不包括在 XCode 分析器/仪器的分配中。但是,您可以看到它影响了“内存监视器”仪器。尽管释放了一些分配,但我也一直在崩溃,因为纹理被泄露了。
【解决方案2】:

如果没有更多信息,我无法知道这些是否适用于您,但我在尝试清理内存警告后通常会遇到某些问题:

  • 未知的循环引用会阻止内存按预期释放。使用仪器来寻找它们。我最近修复了一个我不小心在块中使用 self 导致保留的情况。我们在出现内存警告时注意到了这一点,但我们无法通过释放该资源来很好地从警告中恢复。
  • 清理资源 - 或自动释放资源 - 释放了一些仍然需要的东西。你可能在你不期望的地方有一个 nil,或者你可能对一个僵尸进行操作。检查您的保留和清理,尤其是代表的取消。打开僵尸和异常断点。

通常最好的解决办法是首先防止内存警告发生。

【讨论】:

  • 感谢您的帮助(赞成),但是,这两者都不是:1)当我释放东西时,您可以看到应用程序的内存使用量实际上下降了,2)这不是僵尸问题,因为 iOS 肯定会终止我(我可以从我的 iPad 下载 LowMemory “抛弃”的崩溃日志)。
【解决方案3】:

检查图像转换的代码。 SDWebImage 项目中有一些代码用于缩小图像,对所选图像应用一些变换和旋转技术。它实际上并没有使用太多来缩小尺寸,但有时会引起内存警告。注释该代码并尝试构建您的应用程序。

我在我的应用程序中遇到了同样的问题。我曾试图评论转换代码。问题得到解决。你也可以试试。

【讨论】:

    【解决方案4】:

    2 级内存警告是 Urgent。您的应用可能会在收到 2 级警告之前收到一个或多个 1 级警告,此时您应该采取行动。

    根据我的经验,当您的应用收到 2 级警告时,几乎总是为时已晚,而且无论如何都会被杀死。

    【讨论】:

      【解决方案5】:

      在处理大图像(每张图像 4Mb)时,您可能会面临内存不足的风险,而不会收到内存不足的警告。

      最好的办法是防止您的内存使用量增长过多。图像的加载速度使得缓存很好,但并不是真正必要的。最好在不再使用内存后立即释放内存,从而降低使用率。

      祝你好运,如果你找到值得分享的东西,请告诉我们。

      【讨论】:

        猜你喜欢
        • 2012-05-25
        • 1970-01-01
        • 2016-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-08
        • 2011-12-01
        • 1970-01-01
        相关资源
        最近更新 更多