如何调试由于内存压力导致的 iOS 崩溃

Posted

技术标签:

【中文标题】如何调试由于内存压力导致的 iOS 崩溃【英文标题】:How to debug iOS crash due to memory pressure 【发布时间】:2013-10-15 17:02:49 【问题描述】:

我正在使用 ARC,应用程序崩溃并提示收到内存警告。 我正在设备上直接测试应用程序(带有 ios 7.0.2 的 iPhone 4),并使用 iOS 6 SDK 使用 XCode 5 进行编译。 我使用了苹果仪器,分配了大约 20MB 的 LiveBytes。

4-5 分钟后,我的应用有 30mb 的内存。

在设备上编译和测试应用程序后,我看到几分钟后崩溃,就在内存警告消息之后。为什么使用仪器不会发生崩溃? 但是,我试图解决这个问题一个月并且无法解决问题,我真的需要帮助。 看起来我没有任何泄漏,但我找不到哪里出错了。 提前感谢您的任何建议。

【问题讨论】:

我有一个在我的 iPad 2 上运行良好的应用程序......直到我升级到 iOS 7,现在它由于“内存压力”而崩溃。你知道如何解决这个问题吗? 我遇到了基本相同的问题,如果我在其他地方找不到答案,可能会很快发布另一个问题。 我解决了我的问题,检查我的答案。 【参考方案1】:

我解决了这个问题。在我的情况下,内存压力是由于运行循环循环持续使用内存造成的。该循环每秒执行一次,并处理必须在视图中分析和呈现的数据。另一件事是,该项目最初没有使用 ARC。在将项目转换为 ARC 后出现问题。

在项目转换为 ARC 之前,在循环结束时我直接调用了资源释放。当然,使用 ARC,这是自动完成的,问题就是这样。所以对于运行循环的类,我回到了非ARC版本,并使用了手工制作的技巧来释放我使用的资源。

自动释放池块提供了一种机制,您可以通过该机制放弃对象的所有权,但避免立即释放它的可能性(例如当您从方法返回对象时)。通常,您不需要创建自己的自动释放池块,但在某些情况下,您必须这样做或者这样做是有益的。

@autoreleasepool 
    // Code that creates autoreleased objects.

在自动释放池块结束时,向块内接收到自动释放消息的对象发送释放消息 - 每次在块内向对象发送自动释放消息时,对象都会收到释放消息。

你可以在任何代码段周围放置一个@autoreleasepool 块,但是你真的不应该做我认为你正在做的事情。

与允许 ARC 为您添加保留和释放调用相比,自动释放的效率要低得多,而且它可能不安全。 Autorelease 将所有对象放入“池”中,然后当您超出范围和/或决定转储池时,它会“耗尽”池,并且对象的保留计数减一。

简短的回答:完全忽略 @autorelease 块,除非 Apple 在文档或模板中另有说明(例如,main.m 中会有一个 @autoreleasepool)。

这意味着您的对象可能会在您真正想要它们之前被释放。 @autoreleasepool 块在您有一个非常紧凑的代码循环将实例化然后丢弃大量对象时更有用。例如,一个 for 循环处理一个巨大的数据库并分配字符串对象,然后使用这些字符串对象来填充您创建的类的实例的属性。在这种情况下,当您在 for 循环中时,ARC 可能无法可靠地释放这些对象,您可能需要创建一个自动释放池。

但是,ARC 在紧密循环中不做正确的事情并不常见。它实际上更像是一个非 ARC 概念,您使用 NSAutoreleasePool 并手动将其耗尽。

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI

我希望我能帮助其他有同样问题的人。

【讨论】:

我认为您在这里得出了一个错误的结论,@autoreleasepools 在 ARC 中仍然有用,而不仅仅是在紧密循环中。在处理循环外的大内存 I/O 时,我已经看到 @autorelease 在我的应用程序中解决内存压力问题。另外:***.com/questions/9086913/… @andreapavan。我有同样的问题。我从 Web 服务获得了 5k 条记录,而不是将所有记录插入到数据库中。每次成功插入 3k 记录都比应用程序崩溃。当我插入 5k 记录时,我的循环将运行 5k 时间。那么在循环中实现 autoreleasepool 方法可以吗? 我的情况比较特殊,因为我必须亲身参与一个分几个步骤开发的项目。正如 Shizam 所说,如果您使用 ARC,自动释放池也很有用。通常,您不需要创建自己的自动释放池块,但在某些情况下您必须这样做或者这样做是有益的。我在 ARC 和块自动释放池之间遇到了问题。在旧的实现中,这是手动处理的,我保持这种方式。我在设置中指出该类不使用 ARC,并在必要时使用块自动释放池手动管理内存。 还可以查看@mattjgalloway 这个很棒的回复,它提供了有关使用 ARC 的块 autorelaspool 的更多详细信息。 ***.com/a/9087002/1056493 我的情况和@Coder 一样。你找到那个@Coder 的解决方案了吗?【参考方案2】:
 #pragma mark - Received Memory Warning

//memory pressure ios
- (void)didReceiveMemoryWarning

   [super didReceiveMemoryWarning];

    if ( [self isViewLoaded] && self.view.window == nil )
    
        self.view = nil;
    

    // Dispose of any resources that can be recreated.

【讨论】:

以上是关于如何调试由于内存压力导致的 iOS 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

如何使用crash工具分析Linux内核崩溃转储文件

如何调试导致python崩溃的python脚本

Linux如何调试内存泄漏

Linux如何调试内存泄漏

没有堆栈时如何调试iOS断言失败崩溃

来自调试器的消息:由于内存问题而终止