2015-05-22 128 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類仍然會引用它,從而造成內存泄漏。

讓我知道是否有幫助。