Java Garbage Collection Circular References ile nasıl çalışır?


161

Anladığım kadarıyla, Java'daki çöp toplama, o nesneyi 'işaret etmeyen' bazı nesneleri temizler.

Sorum şu, böyle bir şeyimiz olursa ne olur:

class Node {
    public object value;
    public Node next;
    public Node(object o, Node n) { value = 0; next = n;}
}

//...some code
{
    Node a = new Node("a", null), 
         b = new Node("b", a), 
         c = new Node("c", b);
    a.next = c;
} //end of scope
//...other code

a,, bve cçöp toplanmalıdır, ancak hepsine başka nesneler tarafından atıfta bulunulmaktadır.

Java çöp koleksiyonu bununla nasıl başa çıkıyor? (ya da sadece bir bellek boşaltma mı?)


1
Bkz. Stackoverflow.com/questions/407855/… , özellikle @gnud'dan ikinci yanıt.
Seth

Yanıtlar:


161

Java'nın GC'si, çöp toplama kökünden başlayan bir zincirden erişilemiyorsa nesneleri "çöp" olarak kabul eder, bu nedenle bu nesneler toplanır. Nesneler bir döngü oluşturmak için birbirlerine işaret etseler de, kökten kesilirlerse yine de çöplerdir.

Ek A: Java Platform Performansında Çöp Toplama Hakkında Gerçekler: Kanlı ayrıntılar için Stratejiler ve Taktikler bölümündeki ulaşılamaz nesneler bölümüne bakın .


14
Bunun için bir referansınız var mı? Test etmek zor.
tangens

5
Bir referans ekledim. Ayrıca, ne zaman toplanacağını öğrenmek için bir nesnenin finalize () yöntemini geçersiz kılabilirsiniz (bunun için finalize () kullanmanızı tavsiye ettiğim tek şey budur).
Kertenkele Bill

1
Son yorumu açıklığa kavuşturmak için ... nesne için benzersiz bir kimlik çıktısı veren sonlandırma yöntemine bir hata ayıklama yazdırma ifadesi koyun. Birbirine referans veren tüm nesnelerin toplandığını görebileceksiniz.
Bill the Lizard

4
“... tanıyabilecek kadar akıllı ...” kafa karıştırıcı geliyor. GC döngüleri tanımak zorunda değil - onlar sadece ulaşılamaz, bu nedenle çöp
Alexander Malakhov

86
@tangens "Bunun için bir referansınız var mı?" çöp toplama hakkında bir tartışma. En iyi. Cinas. Hiç.
Michał Kosmulski

139

evet Java Çöp toplayıcı dairesel referans işler!

How?

Çöp toplama kökleri (GC kökleri) adı verilen özel nesneler vardır. Bunlara her zaman ulaşılabilir ve kendi kökünde olan herhangi bir nesne de öyle.

Basit bir Java uygulaması aşağıdaki GC köklerine sahiptir:

  1. Ana yöntemdeki yerel değişkenler
  2. Ana iplik
  3. Ana sınıfın statik değişkenleri

resim açıklamasını buraya girin

Hangi nesnelerin artık kullanılmadığını belirlemek için JVM, çok uygun bir şekilde işaretleme ve süpürme algoritması olarak adlandırılan şeyi aralıklı olarak çalıştırır . Aşağıdaki gibi çalışır

  1. Algoritma, GC köklerinden başlayarak tüm nesne referanslarını dolaşır ve canlı olarak bulunan her nesneyi işaretler.
  2. İşaretli nesneler tarafından kullanılmayan yığın belleğin tamamı geri kazanılır. Sadece boş olarak işaretlenir, esasen kullanılmayan nesnelerden arındırılır.

Dolayısıyla, herhangi bir nesneye GC köklerinden erişilemezse (kendinden referanslı veya döngüsel olarak referanslı olsa bile), çöp toplama işlemine tabi tutulur.

Tabii ki, programcı bir nesneyi iptal etmeyi unutursa, bu bazen bellek sızıntısına neden olabilir.

resim açıklamasını buraya girin

Kaynak: Java Bellek Yönetimi


3
Mükemmel açıklama! Teşekkürler! :)
Jovan Perovic

O kitabı bağladığınız için teşekkürler. Bu ve diğer Java geliştirme konuları hakkında büyük bilgi dolu!
Droj

14
Son resimde, ulaşılamayan bir nesne var, ancak ulaşılabilir nesneler bölümünde.
La VloZ Merrill

13

Bir çöp toplayıcı, CPU kayıtları, yığın ve genel değişkenler gibi her zaman "ulaşılabilir" kabul edilen bazı "kök" yerlerden başlar. Bu alanlarda herhangi bir işaretçi bularak ve işaret ettikleri her şeyi tekrar tekrar bularak çalışır. Tüm bunları bulduktan sonra, her şey çöp.

Tabii ki, çoğunlukla hız uğruna oldukça az varyasyon var. Örneğin, modern çöp toplayıcıların çoğu "nesillerdir", yani nesiller nesillere bölünürler ve bir nesne yaşlandıkça, çöp toplayıcı, o nesnenin hala geçerli olup olmadığını anlamaya çalıştığı zamanlar arasında daha da uzar - sadece uzun bir süre yaşadıysa, daha uzun yaşamaya devam etme şansının oldukça iyi olduğunu varsaymaya başlar.

Bununla birlikte, temel fikir aynı kalır: Her şey, verilebilecek bazı kök şeylerden başlayarak hala kullanılabilir ve daha sonra başka neler kullanımda olabileceğini bulmak için tüm işaretçileri kovalamaya dayanır.

İlginç bir kenara: insanlar genellikle bir çöp toplayıcısının bu kısmı ile uzak prosedür çağrıları gibi şeyler için nesneleri sıralamak için kod arasındaki benzerlik derecesinden şaşırırlar. Her durumda, bazı kök nesne kümesinden başlıyorsunuz ve atıfta bulunulan diğer tüm nesneleri bulmak için işaretçileri takip ediyorsunuz ...


Tanımladığınız şey bir izleme toplayıcısıdır. Başka koleksiyoncular da var. Bu tartışma için özellikle ilgi çekici referans sayma toplayıcıları vardır do döngüleri ile sorun sahip olma eğilimindedir.
Jörg W Mittag

@ Jörg W Mittag: Kesinlikle doğru - referans sayım kullanan (makul derecede güncel) bir JVM bilmiyorum, bu yüzden orijinal soru üzerinde çok fark yaratması olası görünmüyor (en azından benim için).
Jerry Coffin

@ Jörg W Mittag: En azından varsayılan olarak Jikes RVM'nin şu anda bölge tabanlı bir izleme toplayıcısı olan Immix toplayıcısını kullandığına inanıyorum (aynı zamanda referans sayımı da kullanıyor). Bu referans sayımından veya izlemeden referans sayımını kullanan başka bir toplayıcıdan bahsettiğinizden emin değilim.
Jerry Coffin

Biraz karıştım: Recycler Jalapeno'da uygulandı (yapıldı?), Düşündüğüm algoritma, hangi Jikes'te uygulandı (?) Ulterior Referans Sayımı . Tabii ki, Jikes ve özellikle çöp toplama makinelerinin aynı JVM içinde farklı çöp toplayıcıları hızlı bir şekilde geliştirmek ve test etmek için özel olarak tasarlandığı göz önüne alındığında, Jikes'in bunu veya çöp toplayıcıyı kullandığını söylemek oldukça boştur.
Jörg W Mittag

2
Ulterior Referans Sayımı 2003 yılında Immix'i 2007'de tasarlayan aynı kişiler tarafından tasarlandı, bu yüzden sanırım ikincisi muhtemelen öncekinin yerini aldı. URC, diğer stratejilerle birleştirilebilecek şekilde özel olarak tasarlanmıştır ve aslında URC makalesinde, URC'nin izleme ve referans sayımının avantajlarını birleştiren bir toplayıcıya doğru bir basamak taşı olduğu açıkça belirtilmektedir. Sanırım Immix bu koleksiyoncu. Her neyse, Recycler, döngüleri algılayabilen ve toplayabilen saf bir referans sayma toplayıcısıdır: WWW.Research.IBM.Com/people/d/dfb/recycler.html
Jörg W Mittag

13

Haklısın. Tanımladığınız özel çöp toplama formuna " referans sayımı " denir . En basit durumda çalışma şekli (kavramsal olarak, en azından modern referans sayımının en modern uygulamaları aslında oldukça farklı uygulanır), şöyle görünür:

  • bir nesneye başvuru eklendiğinde (örn. bir değişkene veya alana atanır, yönteme aktarılır, vb.), referans sayısı 1 artar.
  • bir nesneye yapılan bir başvuru kaldırıldığında (yöntem geri döner, değişken kapsam dışına çıkar, alan farklı bir nesneye yeniden atanır veya alanı içeren nesne kendiliğinden çöp toplanır), referans sayısı 1 azalır
  • referans sayısı 0'a ulaştığında, nesneye daha fazla referans yoktur, yani artık kimse onu kullanamaz, bu nedenle çöptür ve toplanabilir

Ve bu basit strateji tam olarak beyan ettiğiniz soruna sahiptir: A ve B ve B A referansları A ise, referans sayılarının hiçbiri asla 1'den az olamaz, yani asla toplanmayacaklardır.

Bu sorunla başa çıkmanın dört yolu vardır:

  1. Boşver. Yeterli belleğiniz varsa, döngüleriniz küçük ve nadirdir ve çalışma süreniz kısadır, belki sadece döngüleri toplamamaktan kurtulabilirsiniz. Bir kabuk komut dosyası yorumlayıcısı düşünün: kabuk komut dosyaları genellikle yalnızca birkaç saniye çalışır ve fazla bellek ayırmaz.
  2. Referans sayma çöp toplayıcısını , döngülerle ilgili sorunları olmayan başka bir çöp toplayıcı ile birleştirin . CPython bunu yapar, örneğin: CPython'daki ana çöp toplayıcı bir referans sayma toplayıcıdır, ancak zaman zaman döngüleri toplamak için bir izleme çöp toplayıcısı çalıştırılır.
  3. Döngüleri tespit edin. Ne yazık ki, bir grafikteki döngüleri tespit etmek oldukça pahalı bir işlemdir. Özellikle, bir izleme koleksiyoncusu ile hemen hemen aynı yükü gerektirir, böylece bunlardan birini de kullanabilirsiniz.
  4. Algoritmayı sizin ve benim gibi saf bir şekilde uygulamayın: 1970'lerden beri, döngü tespiti ve referans sayımını, tek bir işlemde ya yapmaktan çok daha ucuz olan akıllı bir şekilde birleştiren çok sayıda ilginç algoritma geliştirildi. ayrı ayrı ya da bir izleme kollektörü yapıyor.

Bu arada, bir çöp toplayıcıyı uygulamanın diğer önemli yolu (ve zaten birkaç kez yukarıda bahsettiğim) izlemektir . Bir izleme toplayıcı, erişilebilirlik kavramına dayanır . Her zaman ulaşılabilir olduğunu bildiğiniz bazı kök kümeleriyle başlarsınız (örneğin, global sabitler veya sınıf, geçerli sözlük kapsamı, geçerli yığın çerçevesi) ve buradan kök kümesinden erişilebilen tüm nesneleri izler , geçiş kümesine erişinceye kadar kök kümesinden erişilebilen nesnelerden erişilebilen tüm nesneler vb. Bu kapanışta olmayan her şey çöp.Object

Bir döngüye yalnızca kendi içinde ulaşılabilir, ancak kök kümesinden ulaşılamadığından, toplanır.


1
Soru Java'ya özgü olduğundan, Java'nın ref sayımı kullanmadığından ve sorun olmadığından bahsetmeye değer olduğunu düşünüyorum. Ayrıca wikipedia bağlantısı "daha fazla okuma" olarak yararlı olacaktır. Aksi takdirde harika bir genel bakış!
Alexander Malakhov

Jerry Coffin'in gönderisine ilişkin yorumlarınızı henüz okudum, bu yüzden şimdi emin değilim :)
Alexander Malakhov

8

Java GC'leri sizin tarif ettiğiniz gibi davranmaz. Sıklıkla "GC kökleri" olarak adlandırılan temel bir nesne kümesinden başladıklarını ve bir kökten ulaşılamayan herhangi bir nesneyi toplayacaklarını söylemek daha doğrudur.
GC kökleri aşağıdakileri içerir:

  • statik değişkenler
  • çalışan bir iş parçacığının yığınında bulunan yerel değişkenler (tüm geçerli 'bu' referanslar dahil)

Dolayısıyla, sizin durumunuzda, a, b ve c yerel değişkenleri yönteminizin sonunda kapsam dışına çıktığında, doğrudan veya dolaylı olarak üç düğümünüzün herhangi birine bir başvuru içeren daha fazla GC kökü yoktur ve çöp toplama için uygun olacaklardır.

İsterseniz TofuBeer'in bağlantısı daha fazla ayrıntıya sahiptir.


"... şu anda çalışan bir iş parçacığının yığınında ..." diğer iş parçacığının verilerini bozmamak için tüm iş parçacıklarının yığınlarını taramıyor mu?
Alexander Malakhov

6

Bu makale (artık mevcut değildir) çöp toplayıcı hakkında derinlemesine incelenmektedir (kavramsal olarak ... birkaç uygulama vardır). Yayınınızla alakalı bölüm "A.3.4 Ulaşılamıyor":

A.3.4 Ulaşılamıyor Bir nesneye daha güçlü referansları olmadığında ulaşılamaz bir duruma girer. Bir nesneye ulaşılamadığında, koleksiyon için bir adaydır. Şuna dikkat edin: Bir nesnenin koleksiyon için aday olması, derhal toplanacağı anlamına gelmez. JVM, nesne tarafından tüketilen belleğe hemen ihtiyaç olana kadar toplama işlemini geciktirir.



1
bağlantılar artık mevcut değil
titus

1

Çöp toplama genellikle "başka bir şey o nesneyi 'işaret etmiyorsa" bazı nesneleri temizle "anlamına gelmez (referans sayımı). Çöp toplama kabaca programdan ulaşılamayan nesneleri bulmak anlamına gelir.

Dolayısıyla, örneğinizde, a, b ve c kapsam dışına çıktıktan sonra, GC tarafından toplanabilir, çünkü artık bu nesnelere erişemezsiniz.


"Çöp toplama kabaca programdan ulaşılamayan nesneleri bulmak anlamına gelir". Çoğu GC algoritmasında aslında tam tersi. GC kökleri ile başlıyorsunuz ve ne bulabileceğinizi görüyorsunuz, gerisi referanssız çöp olarak kabul ediliyor.
Fredrik

1
Referans sayımı , çöp toplama için iki ana uygulama stratejisinden biridir. (Diğeri izliyor.)
Jörg W Mittag

3
@ Jörg: Çoğu zaman, insanlar çöp toplayıcıları hakkında konuştuğunda, bir çeşit mark'n'sweep algoritmasına dayanan koleksiyonculara atıfta bulunuyorlar. Ref sayımı, bir çöp toplayıcıya sahip değilseniz, genellikle sıkıştığınız şeydir. Ref sayımının bir anlamda bir çöp toplama stratejisi olduğu doğrudur, ancak bugün bunun üzerine inşa edilmiş neredeyse hiç gc yoktur, bu yüzden bir gc stratejisi olduğunu söylemek insanları karıştırır, çünkü pratikte artık bir gc değildir. ama hafızayı yönetmenin alternatif bir yolu.
Fredrik

1

Bill sorunuzu doğrudan yanıtladı. Amnon'un dediği gibi, çöp toplama tanımınız sadece referans sayımıdır. Sadece mark ve süpürme ve kopya toplama gibi çok basit algoritmaların bile dairesel referansları kolayca ele aldığını eklemek istedim. Yani, bu konuda sihirli bir şey yok!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.