当 Leaks 工具不显示内存泄漏时如何调试它们?

How to debug memory leaks when Leaks instrument does not show them?

我有一个用 Swift 编写的 iOS 应用程序正在泄漏内存 - 在某些情况下,某些对象应该被释放,但它们没有。我通过简单地添加 deinit 像这样的调试消息了解了这个问题:

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

因此,在应该导致对象释放的此类事件发生后,控制台中应该出现 deinit 消息。但是,对于某些应该释放的对象,消息丢失了。尽管如此,Leaks Developer Tool 并未显示任何泄漏。我该如何解决这种情况?

使用仪器检查由于保留但未泄漏的内存而导致的泄漏和内存丢失。后者是仍指向的未使用内存。在 Instruments 的 Allocations instrument 中使用 Mark Generation (Heapshot)。

有关如何使用 Heapshot 查找内存泄漏,请参阅:bbum blog

基本上方法是 运行 Instruments 分配工具,进行 heapshot,运行 代码迭代并进行另一个 heapshot 重复 3 或 4 次。这将指示在迭代期间分配和未释放的内存。

要弄清楚结果,请查看个人分配。

如果您需要查看对象的保留、释放和自动释放发生在何处,请使用工具:

运行 in instruments,在 Allocations 中设置 "Record reference counts" on(对于 Xcode 5 及更低版本,您必须停止记录才能设置选项)。使应用程序 运行、停止记录、向下钻取,您将能够看到所有保留、释放和自动释放发生的位置。

在Xcode8中,可以点击调试工具栏中的“Debug Memory Graph”按钮,(显示在屏幕底部):

参见 Apple 的 Diagnosing and Resolving Bugs in Your Running App: Visualize and Diagnose Increasing Memory Usage

只需在左侧面板中确定您认为应该被释放的对象,它就会向您显示对象图(如上图 canvas 中所示)。这对于快速识别在相关对象上建立强引用的位置非常有用。从这里开始,你可以开始你的研究,诊断为什么那些强引用没有被解析(例如,如果有问题的对象有来自其他应该被释放的东西的强引用,也看看那个对象的图表,你可能会发现问题(例如强引用循环、重复计时器等)。

注意,在右侧面板中,我看到了调用树。我通过在方案设置中打开“malloc 堆栈”日志记录选项得到了它:

无论如何,完成后,您可以单击上面第一个屏幕快照右侧面板中堆栈跟踪中显示的相关方法调用旁边的箭头,您可以看到那个强引用最初在哪里成立:


传统的 Instruments 技术(如果使用旧版本的 Xcode 尤其有用)在我原来的回答中描述如下。


我建议使用 Instruments 的“分配”工具和“记录引用计数”功能:

然后您可以 运行 Instruments 中的应用程序,然后搜索您知道正在泄漏的 class 并通过单击箭头深入研究:

然后您可以使用右侧的“扩展详细信息”面板深入了解详细信息并查看堆栈跟踪:

在“扩展详细信息”面板中,关注黑色的代码而不是灰色的系统调用。无论如何,从“扩展详细信息”面板,您可以直接在 Instruments::

中钻取您的源代码

更多使用Instruments排查内存问题的资料和演示,请参考: