2015-05-22 25 views
10

Android'de (Java) LeakCanary olarak adlandırılan bellek sızıntısı algılaması için bir kütüphaneye rastladım, ancak belleği kaçıran yeri anlayamıyorum. Herhangi biri, örneklerinde gösterilen kodun nasıl ve neden bir bellek sızıntısı olduğunu açıklayabilir.Bu neden bir bellek sızdırıyor

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; 

ve daha sonra seyretmek (yukarıdaki kod ilişkilendirmek nasıl bilmiyorum) aşağıdaki gibi gösterilen bir sızıntı verir sızıntı değişken schrodingerCat.

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

Sızıntının açıklamasıyla ilgili herhangi bir yardım ve saptamanın bununla ilgili olarak nasıl yardımcı olabileceği çok yardımcı olabilir. Ayrıca yeni başlayanlar için bazı iyi makaleler güzel olurdu.

Teşekkürler!

cevap

13

Öncelikle, bir Bellek Sızıntısı ne olduğunu anlayalım:

Tanımı

bellek sızıntısı RAM tahsis verileri (bitmap'ler, nesneler, diziler, vs) olduğu çöp toplayıcısı Program tarafından artık gerekli olmamasına rağmen (GC) özgür olamaz.

Örnek

Kullanıcı bir resim gösteren bir görünüm açıyor. Bitmap'i belleğe yüklüyoruz. Şimdi, kullanıcı görünümünden çıkmaktadır ve görüntü artık gerekli değildir ve koddan bir referans yoktur. O anda, GC harekete geçer ve onu bellekten kaldırır. BUT, eğer hala bir referansa sahip olsaydık, GC kaldırılmayacağını bilmeyecek ve RAM'in gereksiz yere yer almasına neden olacaktı - aka Bellek Kaçak.Bir Kutu

yılında

Kedi bizim app bir kedi nesnesi var diyelim ve biz bir Kutu nesnesi tutun. Kutuyu tutarsak (Kutu nesnesine bir referans varsa) ve Kutu Kedi'yi tutarsa, GC Cat nesnesini bellekten temizleyemez.

Docker, Kutumuza Statik referans veren bir sınıftır. Bu, onu geçersiz kılmadıkça veya değeri yeniden tahsis etmedikçe, Docker'ın Box'a başvurmaya devam edeceği anlamına gelir. Kutunun (ve iç Kedinin) GC tarafından hafızasından kaldırılmasını önleme.

Yani, Cat'a ihtiyacımız var mı? App için hala geçerli mi?

Bu, Cat için ne kadar zamana ihtiyacımız olduğuna karar vermek için geliştiriciye kalmış. LeakCanary ve diğer tanı araçları, olası bir Bellek Kaçakını öneriyor. Nesnenin (Kedinin) artık gerekli olmayabileceğini düşünürler, böylece bir sızıntı olduğunu uyarırlar.

örnekte

Özeti, bir bellek sızıntısı ortak senaryosu verir. Bir Statik referansı kullanırken, GC'nin bir Nesneyi temizlemesini önleriz. Bunu şöyle olmalıdır: kudretinin artık kullanılmamaktadır edilmesi ancak GC ile bellekten kaldırılmadı

  • Nesne Cat: olarak

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

    .

  • Kedinin çıkarılmadığı nedenin nedeni, Box'un kendisine bir başvuru yaptığı için.
  • Nesnenin çıkarılmadığı nedeni, Docker'ın statik bir referansı olduğundan dolayı.
  • Docker tarafından yapılan statik referans, olası sızıntıya neden olan ağacın ROOT'udur.
+1

Bu büyük açıklama LeakCanary'nin wiki'sine eklenmelidir :) – tieorange

1

O "sızıntı değişken schrodingerCat izlemek" için kullanılan RefWatcher örneği gibi görünür:

refWatcher.watch(schrodingerCat); 

GC kümesi geçer ve bu GC sırasında alınmaz geçirilen referans geçerse o kabul edilir zorlar Bir sızıntı. Bunu kontrol etmek için RefWatcher sorduğunuzda statik Docker.container.hiddenCat yana

, o kadar GC'ed edilemez aslen schrodingerCat olarak bilinen nesneye bir GC köklü referansı tutuyor. Bu nedenle, nesnenin toplanamayacağını bilmenizi sağlar.

+1

huh? Benim için biraz daha fazla dilsiz olabilir misiniz :) – Bootstrapper

+0

'Docker.container.hiddenCat', 'schrodingerCat' olarak oluşturulan nesneye statik bir referanstır. Yani bu nesne, 'RefWatcher' bu nesne için aktive edildiğinde çöp toplanamaz. –

1

Sana Muhtemelen Yukarıdaki örneği anlamanıza yardımcı olacaktır bu cevabı https://stackoverflow.com/a/11908685/1065810

okumak öneririz.

Özetle, örneğinizde, Docker sınıfı bir Kutuya referans tutar. Konteyner kutusu artık gerekli olmadığında bile, Docker sınıfı hala bir referans alır ve böylece bir bellek sızıntısı yaratır.

Yardım edin eğer bana bildirin.

İlgili konular