当Leaks工具未显示内存泄漏时,如何调试内存泄漏?

72

我有一个使用Swift编写的iOS应用程序存在内存泄漏问题 - 在某些情况下,一些对象应该被释放但并没有被释放。通过添加类似于 deinit 的调试消息,我已经了解到了这个问题:

deinit {
    println("DEINIT: KeysProvider released")
}

因此,在应该导致对象释放的事件之后,deinit消息应该出现在控制台中。然而,对于一些应该被释放的对象,该消息却丢失了。尽管如此,Leaks开发者工具并未显示任何泄漏。我该如何解决这种情况?


我不确定那是一个好的测试。你的代码中可能仍然有某个地方持有指向这些例程的指针。或者Swift编译器足够聪明,如果不需要调用deinit,就不会调用它。你需要一个更好的测试来检测内存泄漏。 - zaph
2个回答

153
在Xcode 8中,您可以点击调试工具栏底部显示的“Debug Memory Graph”按钮debugmemorygraphbutton

debug memory graph

请查看苹果公司的《诊断和解决运行应用中的错误:可视化和诊断内存使用量增加》

只需在左侧面板中找到您认为应该被释放的对象,它就会显示对象图(显示在主画布上方)。这非常有用,可以快速确定在疑问对象上建立强引用的位置。从这里开始,您可以开始研究,诊断为什么这些强引用没有被解决(例如,如果疑问对象从其他应该被释放的东西中获得了强引用,请查看该对象的图表,您可能会发现问题(例如,强引用循环,重复定时器等)。

请注意,在右侧面板中,我正在查看调用树。我通过在方案设置中打开“malloc stack”日志记录选项来获得它:

malloc stack

无论如何,完成这一步后,您可以单击第一个屏幕截图右侧面板中显示的堆栈跟踪中相关方法调用旁边的箭头,然后您可以查看最初建立该强引用的位置:

code


传统的Instruments技术(在使用旧版本的Xcode时特别有用)将在下面的原始回答中进行描述。
我建议使用Instruments的“Allocations”工具,并启用“Record Reference Counts”功能:

record reference counts

你可以在Instruments中运行应用程序,然后搜索你知道存在内存泄漏的类,并通过点击箭头进一步查看:

enter image description here

你可以使用右侧的“扩展细节”面板,深入了解详情并查看堆栈跟踪:

extended details

在“扩展详情”面板中,重点关注黑色代码而不是灰色系统调用。无论如何,在“扩展详情”面板中,您都可以直接进入Instruments中的源代码。

your code

如需更多关于使用Instruments跟踪内存问题的信息和演示,请参考以下内容:


谢谢。您建议的方法可能是检测强周期使用工具的最佳方法。然而,这仍然不太有用。我可以看到当前特定类的引用计数,但我真正需要的是哪些对象持有这些引用...但这是工具设计上的问题,您的答案很棒。谢谢! - Rasto
它不仅会向您显示引用计数是多少,更重要的是,它会向您展示这些强引用是在哪里建立的。我以强引用循环为例,但它适用于任何所有权场景。 - Rob
2
您可以通过选择"未配对"保留/释放(请参见第三个快照的顶部按钮)来缩小范围,这样就不必浏览所有的内容。但是,在此之后,您可能仍需要手动处理其余的内容。虽然不完美,但您应该能够相当快速地缩小范围。 - Rob
或者更好的方法是使用新的Xcode 8“Debug Memory Graph”工具,您可以快速识别出杰出的强引用所在位置,如我上面修改后的答案所示。 - Rob
使用这个方法我解决了强引用问题。但同时,我发现了内存泄漏问题,哎呀!准备修复它。 - Zhou Haibo
显示剩余3条评论

2
使用仪器检测泄漏和保留但未泄漏的内存丢失。后者是指仍然被指向的未使用内存。在Instruments的Allocations仪器上使用Mark Generation(Heapshot)功能。
有关如何使用Heapshot查找内存增长的详细说明,请参见:bbum博客
基本方法是运行Instruments的分配工具,拍摄一个堆快照,运行代码的一个迭代,并再次拍摄堆快照重复3或4次。这将显示在迭代期间分配但未释放的内存。
要查看结果,请披露以查看各个分配。
如果需要查看对象的保留、释放和自动释放发生的位置,请使用Instruments:
在Instruments中运行,在Allocations中打开“记录引用计数”选项(对于Xcode 5及更低版本,您必须停止记录才能设置该选项)。导致应用程序运行,停止记录,深入挖掘,您将能够看到所有保留、释放和自动释放发生的位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接