为什么这是内存泄漏

Why is this a memory leak

我在 Android (Java) 中遇到了一个名为 LeakCanary 的内存泄漏检测库,但无法理解它们泄漏内存的示例。谁能解释一下他们的示例中显示的代码如何以及为什么会发生内存泄漏。

class Cat {
}
class Box {
  Cat hiddenCat;
}
class Docker {
  static Box container;
}

// ...

Box box = new Box();
Cat schrodingerCat = new Cat();
box.hiddenCat = schrodingerCat;
Docker.container = box;

然后他们观察变量 schrodingerCat 是否有泄漏,泄漏如下所示(我不知道如何与上面的代码相关)。

* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance

对泄漏的解释以及检测与泄漏的关系的任何帮助都将非常有帮助。也有适合初学者的好文章。

谢谢!

看起来 RefWatcher 实例用于 "watch the variable schrodingerCat for leaks":

refWatcher.watch(schrodingerCat);

强制执行一组 GC 传递,如果传入的引用在这些 GC 传递期间未被收集,则视为泄漏。

由于静态 Docker.container.hiddenCat 保留了对最初称为 schrodingerCat 的对象的 GC 根引用,所以当您要求 RefWatcher 检查时,它无法被 GC它。因此它让您知道该对象无法收集。

我建议你阅读这个答案

它可能会帮助您理解上面的示例。

简而言之,在您的示例中,class Docker 保留对 Box 的引用。即使不再需要容器盒,class Docker 仍然持有对它的引用,从而造成内存泄漏。

如果有帮助请告诉我。

首先,让我们了解什么是内存泄漏

定义

内存泄漏 是在垃圾收集器 (GC) 无法释放的 RAM 中分配的数据(位图、对象、数组等),尽管不再需要它通过程序。

例子

用户正在打开显示图像的视图。我们将位图加载到内存中。现在用户退出视图,不再需要图像,代码中也没有对它的引用。在那一刻,GC 开始行动并将其从内存中删除。 但是,如果我们仍然有对它的引用,GC 将不知道它可以被删除并且它会留在 RAM 中占用不需要的 space - 又名 内存泄漏.

盒子里的猫

假设我们的应用程序中有一个 Cat 对象,我们将它保存在一个 Box 对象中。如果我们持有盒子(拥有对 Box 对象的引用)并且 Box 持有 Cat,GC 将无法从内存中清除 Cat 对象。

Docker 是一个 class,它有一个对我们的 Box 的静态引用。这意味着除非我们取消它或重新分配值,否则 Docker 将继续引用 Box。防止 Box(和内部 Cat)被 GC 从内存中删除。

那么,我们需要猫吗?它仍然与应用程序相关吗?

这由开发人员决定我们需要 Cat 多长时间。 LeakCanary 和其他诊断工具提示可能存在内存泄漏。他们认为可能不再需要该对象 (Cat),因此他们警告说这是泄漏。

回顾

在示例中,他们给出了内存泄漏的常见场景。当使用 Static 引用时,我们会阻止 GC 清理对象。你应该阅读这篇文章:

* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance

如:

  • 对象 Cat 可能 不再使用但未被 GC 从内存中删除。
  • 未删除对象 Cat 的原因是 Box 引用了它。
  • 对象 Box 未被删除的原因是 Docker 对其有静态引用。
  • Docker 的静态引用是导致可能泄漏的树的 ROOT。