在Xcode中查找泄漏

Swift和Objective C都使用自动引用计数(ARC)来跟踪何时需要将对象保留在内存中以及何时可以安全地释放该对象。

内存泄漏是在创建对象并将其保留在内存中后,不再属于任何事物,并且永远无法释放。 通常,这是一种循环依赖关系,其中对象A拥有对象B,而对象B拥有对象A。它们彼此都将保留在内存中,因为它们彼此都是必需的。 所谓“拥有者”,是指“拥有强烈的参照权”。

泄漏通常在委托模式中看到。 委托引用应始终声明为weak引用,因为弱引用将允许运行时释放内存。 考虑到父母/孩子的关系,父母应该对孩子有strong的指称,但是孩子应该对父母有weak的指称。 在Swift中,默认情况下引用strong

另一个常见的泄漏地方是在密封盖内。 在闭包中使用的所有变量(包括self)都将被强烈捕获,以确保在闭包执行时它们仍然存在。 为了避免此处的保留周期,请使用捕获列表告诉闭包保留弱引用。

请注意,这不必适用于所有闭包,仅适用于@escaping那些,这意味着它们将被存储以供以后执行。 John Sundell对此发表了一篇出色的文章,即在Swift闭包中捕获对象。

例如:

  object.run {res-> Void in 
self.result = res
}

会泄漏self

通过在捕获列表中适当的weakunowned来解决此问题:

  object.run {[弱自我] res->无效 
self?.result = res
}

这种基本的方法涉及日志记录。 首先在要检查的类的init方法中放置一个打印语句。 我喜欢使用表情符号,以便在控制台中轻松查看。

 在里面() { 
打印(“✅初始化我的班级”)...
}

并将另一个打印语句放在deinit方法中。

  deinit { 
print(“❌取消我的课程”)
}

现在运行该应用程序,并使用分配该类的功能,然后完成它,以便释放该类(例如,提供一个视图控制器,然后将其关闭)。 您应该看到平衡数量的日志,例如,每个init一个deinit 。 如果没有看到deinit日志,则可能是您的对象泄漏了。

您可以使用断点代替日志,并且对于奖励点,在发生重新分配时会播放“ pop”声。

在模拟器中调试时,这是Xcode中可用的运行时工具。 首先,请编辑方案并启用Malloc Stack

接下来,运行您的项目,并运行该应用程序以生成泄漏。 例如,如果您怀疑某个视图控制器正在泄漏,请多次显示/推送和关闭/弹出该视图控制器。 然后启动内存图工具。

如果有泄漏,则可能会或可能不会自动以紫色提示突出显示该泄漏,因此请仅将其作为线索。

在上面的屏幕截图中,我们可以看到TimeEntryViewController旁边有(4) ,表示内存中有4个实例在浮动。 选择一个以查看导致周期的所有权链。 如果您真的很幸运(如上文所述),您甚至会获得有用的堆栈跟踪,单击该堆栈跟踪将直接导航到捕获对象的代码行。

Xcode还提供了用于检测泄漏的仪器工具,这是皮带上的便捷工具。

如果要播放,请运行Xcode -> Product -> Profile以启动Instruments,然后选择Leaks模板。 加载后,按“录制”按钮以在模拟器中启动应用程序。

当应用程序运行时,使用它并观察“ Leak Checks行,当检测到泄漏时,它将用红叉标记。 单击它以查看堆栈跟踪。

由于现代设备的内存要比第一代iPhone多得多,因此由于内存消耗过多而导致应用崩溃的情况很少见。 但是,始终值得避免泄漏,因为它们通常会在运行时导致其他问题或错误。

希望这篇文章可以帮助您弥补应用程序中的一些漏洞。


最初发布在 www.nextfaze.com