Çöp toplamada bir karma tablo kullanmak, dünyadaki markalama ve süpürme sorununu durdurur mu?


13

Mark-sweep-compact çöp toplama algoritmasında nesneleri değiştirirken dünyayı durdurmanız gerekir çünkü referans grafiği tutarsız hale gelir ve nesneyi işaret eden tüm referansların değerlerini değiştirmeniz gerekir.

Ancak, anahtar olarak nesne kimliği ve değer olarak işaretçi içeren bir karma tablonuz olsaydı ve referanslar, nesne adresi yerine adı geçen kimliğe işaret ederse ... referansların düzeltilmesi yalnızca bir değerin değiştirilmesini gerektirir ve duraklama yalnızca nesne kopyalama sırasında yazılmaya çalışılır ...

Düşüncemde bir hata var mı?

Yanıtlar:


19

Duraklatma gerektiren tek şey referansları güncellemek değildir . Genel olarak "mark-sweep" altında gruplanan standart algoritmaların tümü, nesne grafiğinin tamamı işaretlenirken değişmeden kaldığını varsayar. Değişikliklerin doğru şekilde işlenmesi (oluşturulan yeni nesneler, referanslar değişti), üç renkli algoritma gibi oldukça alternatif alternatif algoritmalar gerektirir. Şemsiye terimi "eşzamanlı çöp toplama" dır.

Ancak evet, sıkıştırmadan sonra referansları güncellemek de bir duraklamaya ihtiyaç duyar. Ve evet, dolaylı (örn. Kalıcı nesne kimliği ve karma tablo aracılığıyla gerçek işaretçiler) kullanmak duraklamayı büyük ölçüde azaltabilir. İstenirse bu parçayı kilitsiz hale getirmek bile mümkün olabilir. Herhangi bir düşük seviyeli paylaşılan bellek eşzamanlılığı kadar doğru olmak yine de zor olurdu, ancak işe yaramaması için temel bir neden yoktur.

Bununla birlikte , ciddi dezavantajları olacaktır. Fazladan yer almanın yanı sıra ( tüm nesneler için en az iki ekstra kelime) her dereferansı çok daha pahalı hale getirir . Bir özellik almak kadar basit bir şey bile artık tam bir karma tablo araması içeriyor. Performans vuruşunun artımlı izlemeden çok daha kötü olacağını tahmin ediyorum.


Peki bugün çok fazla belleğimiz var, bu yüzden 50 Mb masa diyelim ve karma basit modulo olabilir, bu yüzden sadece bir talimat ...
mrpyo

3
@mrpyo karma tablonun boyutunu getirme, modulo işlemi, gerçek nesne işaretçisini elde etmek için karma tablo ofsetinden dereference, nesnenin kendisine dereference. Artı muhtemelen bazı kayıt karıştırma. Sonunda 4'ten fazla talimatla karşılaşıyoruz. Ayrıca, bu şemanın bellek konumuyla ilgili sorunları vardır: Şimdi hem hash tablosu hem de verinin kendisi önbelleğe sığmalıdır.
amon

@mrpyo Nesne başına bir girişe (nesne kimliği -> geçerli adres) ihtiyacınız var değil mi? Ve hash fonksiyonunun ne kadar ucuz olduğuna bakılmaksızın, çarpışmalarınız olacak ve bunları çözmeniz gerekecek. Ayrıca amon ne dedi.

@ amon CPU'ların 50MB veya daha fazla önbelleğe sahip olması sadece bir zaman meselesi :)
Móż

1
@ Ӎσᶎ Zamanla, bir yongaya 50 MiB transistör koyabilir ve hala L1 veya L2 önbellek olarak çalışacak kadar düşük gecikmeye sahip olabiliriz (L3 önbellekleri zaten 15 MiB boyutundadır, ancak genellikle yonga dışı AFAIK ve uzak L1 ve L2'den daha kötü gecikme), buna bağlı olarak büyük miktarlarda ana belleğe (ve içine yerleştirilecek verilere) sahip olacağız. Tablo sabit boyutta olamaz, yığınla birlikte büyümelidir.

19

Bilgisayar bilimlerindeki tüm sorunlar, çok fazla dolaylı katman sorunu hariç, başka bir dolaylı düzey ile çözülebilir.

Yaklaşımınız çöp toplama sorununu hemen çözmez, ancak sadece bir seviye yukarı taşır. Ve ne pahasına! Şimdi, her bellek erişimi başka bir işaretçi referansından geçer. Sonuç konumunu önbelleğe alamayız, çünkü bu arada başka bir yere taşınmış olabilir, her zaman nesne kimliğinden geçmeliyiz. Çoğu sistemde, bu dolaylı yayın kabul edilemez ve dünyayı durdurmanın toplam çalışma zamanı maliyetinin daha düşük olduğu varsayılır.

Teklifinizin sorunu çözdüğünü değil, yalnızca hareket ettiğini söyledim. Sorun, nesne kimliklerinin yeniden kullanılmasıyla ilgilidir. Nesne kimlikleri artık bizim işaretçilerimize eşdeğerdir ve yalnızca sınırlı miktarda adres vardır. Programınızın ömrü boyunca, örneğin bir döngü gibi INT_MAX nesnelerinden daha fazlasının oluşturulduğu düşünülebilir (özellikle 32 bit sistemde).

while (true) {
    Object garbage = new Object();
}

Her nesne için nesne kimliğini artırdığımızda, bir noktada kimlikler tükenir. Bu nedenle, hangi kimliklerin hala kullanımda olduğunu ve hangilerinin geri alınabilmesi için ücretsiz olduğunu bulmalıyız. Kulağa tanıdık geliyor mu? Şimdi ilk kareye geri döndük.


Muhtemelen 256 bit bignum dediği gibi 'yeterince büyük' ​​kimlikler kullanılabilir mi? Bu fikrin genel olarak iyi olduğunu söylemiyorum, ancak neredeyse kesinlikle IDS'yi tekrar kullanabilirsiniz.
Vality

@Gerçekliksel olarak evet - gördüğümüz kadarıyla, kimlik tekrar kullanımı sorununu çözecek. Ama bu sadece başka bir “640K herkes için yeterli olmalı” iddiasıdır ve problemi çözmez. Daha feci bir yönü, tüm nesnelerin (ve karma tablosunun) boyutunun bu büyük boyutlu sahte işaretçileri barındırmak için artması gerektiğidir ve karma erişimi sırasında bu bigint'i muhtemelen birden fazla kayıt tutacak diğer kimliklerle karşılaştırmamız gerekir. ve tamamlamak için birden fazla talimat alın (64bit: 8 × yük, 4 × karşılaştırma, 3 × ve yerel girişlere göre 5 × artış).
amon

Evet, bir süre sonra kimlikleriniz tükenir ve bir duraklama gerektiren hepsini değiştirmeniz gerekir. Ama muhtemelen nadir bir olay olurdu ...
mrpyo

@ amon Çok fazla hemfikir, hepsi çok iyi noktalar, katılıyorum gerçekten sürdürülebilir bir sisteme sahip olmak çok daha iyi. Bu ne yaparsanız yapın dayanılmaz derecede yavaş olacaktır, ancak teoride ilginçtir. Şahsen ben yine de büyük bir çöp toplayıcı fan değilim: P
Vality

@amon: dünyada 64 bit ID'yi (584 yıllık nanosaniye) bir kez kaydırdığınızda yanlış olacak olandan daha fazla kod var ve muhtemelen özellikle küresel sayacı kırmazsanız bellek tahsisini 1ns alacak şekilde düzenleyebilirsiniz. kimlikler tükürüyor!). Ama elbette, buna güvenmene gerek yoksa.
Steve Jessop

12

Düşüncelerinizde bir hata yok, sadece orijinal Java çöp toplayıcının nasıl çalıştığına çok yakın bir şey tarif ettiniz

Orijinal Java sanal makinesi [6] ve bazı Smalltalk sanal makineleri, nesnelere başvurmak için [6] 'da tutamaç adı verilen dolaylı işaretçiler kullanır. Kulplar, çöp toplama sırasında nesnelerin kolayca yer değiştirmesine izin verir, çünkü kulplarla, her nesneye yalnızca bir doğrudan işaretçi vardır: sapındaki. Han-dle aracılığıyla dolaylı olarak nesneye yapılan tüm diğer referanslar. Bu tür tutamaç tabanlı bellek sistemlerinde, nesne adresleri nesnelerin ömrü boyunca değişir ve bu nedenle karma için kullanılamazken, tutamaç adresleri sabit kalır.

Çöp Toplanan Nesnelerin Alanı ve Zaman Verimli Karması

Sun'ın Java Virtual Machine uygulamasının geçerli uygulamasında, bir sınıf örneğine başvuru, kendisi bir çift işaretçi olan bir tanıtıcıya bir işaretçi: biri nesnenin yöntemlerini içeren bir tabloya ve sınıf nesnesini temsil eden bir Class nesnesine işaretçi nesnenin türü, diğeri ise nesne verileri için Java yığınından ayrılan belleğe.

Java Sanal Makine Özellikleri (1997)

Bu yüzden işe yarıyor, denendi ve verimsizliği kuşaksal işaret ve süpürme sistemlerinin gelişmesine yol açtı.


Muhtemelen bu tutamaçlar bir hashtable içindeki anahtarlar değildi (sorudaki gibi)? Gerek yok, sadece işaretçi içeren bir yapı. Daha sonra tutamaklar aynı boyuttadır, böylece bir yığın ayırıcıdan tahsis edilebilirler. Hangi doğası gereği parçalanmadığı için iç sıkıştırmaya ihtiyaç duymaz. Bu ayırıcı tarafından kullanılan büyük blokların kendilerinin yer değiştirememesine yas tutabilirsiniz. Hangi başka bir dolaylı seviye ile çözülebilir ;-)
Steve Jessop

@SteveJessop evet, gc uygulamasında bir hashtable yoktu, ancak sapın değeri de döndürülen değerdiObject.getHashCode()
Pete Kirkham
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.