是否有工具或方法可以在我的 SWIFT 代码中定位强引用循环?
强引用循环是当两个类实例在没有适当安全措施(weak
/ unowned
)的情况下相互引用时,因此一旦我创建的所有变量停止引用这些对象,垃圾收集器就无法处理它们。
是否有工具或方法可以在我的 SWIFT 代码中定位强引用循环?
强引用循环是当两个类实例在没有适当安全措施(weak
/ unowned
)的情况下相互引用时,因此一旦我创建的所有变量停止引用这些对象,垃圾收集器就无法处理它们。
在 Swift 中查找强引用循环的方法与在 Objective-C 中相同。
您可以从 Xcode 运行应用程序,充分锻炼应用程序以显示循环,然后点击“调试内存图”按钮 ( )。然后您可以在左侧面板中选择一个未释放的对象,它会显示内存图,通常可以清楚地说明强引用循环:
有时内存周期并不那么明显,但您至少可以看到哪个对象保持对相关对象的强引用。如有必要,您可以向后跟踪并确定是什么保持了对它的强引用,依此类推。
有时知道什么样的对象保持强引用是不够的,你真的想知道强引用是在代码中的什么位置建立的。“malloc stack”选项,如https://stackoverflow.com/a/30993476/1271826所示,可用于识别建立此强引用时调用堆栈是什么(通常让您识别精确的代码行建立这些强有力的参考资料的地方)。有关详细信息,请参阅 WWDC 2016 视频Visual Debugging with Xcode。
您还可以使用 Instruments 来识别泄漏的对象。只需使用 Allocations 工具通过 Instruments 运行应用程序,反复(不仅仅是一次或两次)将应用程序返回到某个稳态条件,如果内存继续增加,那么您可能有一个强大的参考周期。您可以使用分配工具来确定哪些类型的对象没有被释放,使用“记录引用计数”功能来准确确定这些强引用的建立位置等。
有关识别和解决内存问题的介绍,请参阅 WWDC 2013 视频修复内存问题和 WWDC 2012 视频iOS 应用性能:内存。那里提出的基本技术今天仍然适用(尽管 Instruments 工具的 UI 发生了一些变化……如果您想了解稍微改变的 UI,请参阅 WWDC 2014 视频使用 Instruments 改进您的应用程序)。
顺便说一句,“垃圾收集”指的是一个非常不同的内存系统,在这里并不适用。
使用仪器检查泄漏和记忆丢失。在 Instruments 上的 Allocations 工具中使用标记生成(Heapshot)。
有关如何使用 Heapshot 查找内存占用,请参阅:bbum 博客
基本上,该方法是运行 Instruments allocate 工具,获取一个 heapshot,运行代码的迭代并获取另一个 heapshot,重复 3 或 4 次。这将指示在迭代期间已分配但未释放的内存。
要弄清楚结果,请查看个人分配。
如果您需要查看对象使用工具的保留、释放和自动释放发生的位置:
在仪器中运行,在分配中设置“记录引用计数”(对于 Xcode 5 及更低版本,您必须停止记录以设置选项)。使应用程序运行、停止记录、向下钻取,您将能够看到所有保留、释放和自动释放发生的位置。
非常简单的方法是在 deinitialiser 中打印
deinit {
print("<yourviewcontroller> destroyed.")
}
确保您看到此行打印在控制台上。将 deinit 放入所有视图控制器中。如果您无法看到特定的视图控制器,则意味着它们是一个参考周期。可能的原因是委托很强大,闭包捕获了自我,计时器没有被入侵等。
你可以使用 Instruments来做到这一点。正如本文最后一段所说:
一旦 Instruments 打开,您应该启动您的应用程序并进行一些交互,特别是在您要测试的区域或视图控制器中。任何检测到的泄漏都将在“泄漏”部分显示为红线。助手视图包括一个区域,仪器将在其中向您显示泄漏中涉及的堆栈跟踪,让您深入了解问题可能出在哪里,甚至允许您直接导航到有问题的代码。