View Controllers deinitialized 仍然内存泄漏

View Controllers deinitialized still memory leak

我的所有 VC 中都有 deinit 方法来检查它们是否被取消初始化

 deinit {
        print("\(self.description) successfully deinitialized")
    }

当我注销时,我看到我所有的视图控制器都被取消初始化并且我的 LoginViewController 成为根视图控制器。但我仍然可以看到 RAM 使用量为 90MB。每次我登录和注销时,它都在不断增加。 如果我的视图控制器已取消初始化,它是否可能仍然存在内存泄漏?

据我所知,如果视图控制器被取消初始化,则不会发生内存泄漏。如果存在内存泄漏,视图控制器将不会取消初始化。

我错了吗?请帮忙。

更新: 根据 Luca 的建议,在 回答的帮助下,我发现了内存泄漏。但我无法理解这些。有没有办法让它更具可读性?

内存问题分为三种类型:

  1. 废弃的内存: 这是您确实有一些挥之不去的强引用的内存,但您不再能够访问这些引用。典型的例子就是强引用循环

    这是 Swift 项目中非常常见的问题。您可以使用“调试内存图”功能找到这些。参见 iOS app with ARC, find who is owner of an object or

    顺便说一句,您显然已经确认您的视图控制器正在发布。如果真是这样,那就太好了。但它们并不是唯一可以纠缠在强引用循环中的对象。任何引用类型都可能陷入引用循环。使用“Debug Memory Graph”功能并检查左侧面板中的对象,确保没有不应该存在的对象。 (顺便说一下,这种技术可以让你不必到处散布 deinit 方法。)

  2. 缓存内存:这是已分配的内存,系统会挂起它以防您再次需要它,为您提供高性能访问。除非消耗的内存量很大,否则这通常不会太令人担忧,因为当设备处于内存压力时,通常会自动为您回收这些内存。

    如果使用UIImage(named:)可以在内存中缓存图片。如果您使用 URLSessionURLCache 可以缓存响应。

    如果在模拟器上测试,您可能需要选择“调试”»“模拟内存警告”并查看检索了多少内存(如果有)。

  3. 泄漏内存: 这是已分配的内存,但您没有进一步引用它。这通常是一些手动分配的内存从未被释放的结果。

    Leaks 工具将帮助您找到这些,但是在 Swift 代码中包含此类 material 的任何东西是相对不常见的。 (或者如果你确实有它们,它们往往是框架内生成的小东西,而不是你的控制。)当然,如果你正在进行手动 Core Foundation(或 Core Graphics)调用,你可以表现出这些问题,但不是很常见。

    FWIW,泄漏工具似乎没有报告任何 material 内存消耗。所以专注于分配工具(或者,如果可以的话,更好的是“调试内存图”)。你的泄漏似乎不足以解释你在这里谈论的那种记忆丧失。

此外,我建议您确认您没有打开内存诊断。例如。像僵尸之类的东西会导致内存增长(虽然我不认为你可以接近 90mb 的价值)。诸如 malloc 堆栈跟踪等工具会增加内存消耗。使用这些工具诊断问题时这很好,但完成后应将其关闭。

但是,最重要的是,在深入研究泄漏之前,我会专注于确认问题不是遗弃或缓存内存(因为后者通常很小并且与代码中的任何内容都无关)。这些是更常见的问题来源。

即使 ViewController 被取消初始化,也不一定意味着它会被取消分配。有可能存在强大的参考循环。或者也许在您的代码中,为了避免保留循环,您在某处使用 unowned 引用,引用计数不会变为零。在 strongunowned 引用计数都变为零之前,不会取消分配该对象。在这种情况下,请尝试使用 weak 而不是 unowned 并查看它是否有效。弱引用指向称为 side table 的东西而不是直接指向对象,因此一旦取消初始化就不会阻止对象被释放

查看 this article 以了解无主引用有时如何阻止对象被释放,以及一般的 ARC。