2015-05-22 259 views
10

我遇到了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 

任何帮助解释泄漏以及如何检测与它有关将是非常有益的。也有一些适合初学者的好文章会很好。

谢谢!

回答

13

首先,让我们明白什么是内存泄漏

定义

内存泄漏是分配的数据(位图,对象,数组等)的RAM垃圾回收(GC)无法释放,但该程序不再需要它。

的用户被打开视图,显示一个图像。我们将位图加载到内存中。现在用户退出视图并且不再需要图像,并且代码中没有提及它。此时GC启动并将其从内存中移除。 但是,如果我们仍然有一个引用它,GC不会知道它可以移除,它会留在RAM不需要的空间 - 又名内存泄漏

猫在一个盒子里

比方说,我们在我们的应用程序有一个猫的对象,我们在一个盒子对象持有它。如果我们拿着盒子(对盒子对象有一个引用)并且盒子包含Cat,则GC将无法从内存中清除Cat对象。

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

那么,我们需要猫吗?它是否仍然适用于该应用程序?

这取决于开发者决定我们需要Cat多长时间。 LeakCanary和其他诊断工具提示可能的内存泄漏。他们认为物体(猫)可能不再需要,所以他们警觉它是泄漏。

重温

在该示例中,它们给出了内存泄漏的一种常见的方案。当使用静态参考时,我们阻止GC清除对象。你应该阅读:

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

为:

  • 对象猫威力了不使用,但是从内存中由GC未被删除。
  • 对象猫没有被删除的原因是因为Box有一个对它的引用。
  • 对象框未被删除的原因是因为Docker对它有一个静态引用。
  • Docker的静态引用是导致可能泄漏的树的ROOT。
+1

这个很好的解释应该添加到LeakCanary的wiki中:) – tieorange

1

它看起来像用于“观察的变量schrodingerCat泄漏”的RefWatcher实例:

refWatcher.watch(schrodingerCat); 

迫使一组GC的流逝,如果这些GC期间不收集通过引用传递它被认为是泄漏。

由于静态Docker.container.hiddenCat保持GC最初称为schrodingerCat的对象的引用,因此当您要求RefWatcher检查它时,它不能被GC'ed。因此它可以让你知道该对象不能被收集。

+1

呵呵?你能不能把它贬低一些给我:) – Bootstrapper

+0

'Docker.container.hiddenCat'是一个静态引用,创建为'schrodingerCat'。因此,在该对象的'RefWatcher'被激活时,该对象不能被垃圾收集。 –

1

我建议你阅读这个答案https://stackoverflow.com/a/11908685/1065810

它可能会帮助你理解上面的例子。

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

让我知道是否有帮助。