Ana içeriğe geç
Programlama

G1GC çöp toplayıcısında Arrays.fill işleminin 265 kat yavaşlama nedeni açıklandı

Öne çıkanlar

  • ParallelGC işlem başına 525 mikrosaniye sürerken G1GC aynı donanımda 139 bin mikrosaniyeye ulaştı.
  • Bölge eşiğini 16 bayt aşan dizi doğrudan eski nesil bölgeye yerleştirildi.
  • G1GC yazma bariyerinin üç hızlı çıkış denetimi de başarısız olunca her atamada tam bellek engeli çalıştı.

Java uygulamalarında nesne dizilerini doldurmak için sıkça kullanılan Arrays.fill metodu, G1GC çöp toplayıcısı altında ParallelGC'ye kıyasla 265 kat daha yavaş çalıştı. Bir geliştirici, 1 milyon elemanlı iki nesne dizisi üzerinde yaptığı JMH kıyaslama testinde, ParallelGC ile 0,5 milisaniyede tamamlanan işlemin G1GC üzerinde 139 milisaniye sürdüğünü belirledi. Her iki testte de bellek ayırma ya da çöp toplama döngüsü bulunmamasına rağmen mutator iş parçacığının JIT tarafından üretilen makine kodunda takıldığı anlaşıldı.

ARM64 mimarisi üzerinde yürütülen assembly ve JIT profilleme incelemeleri, yavaşlığın G1GC yazma bariyerinden (write barrier) kaynaklandığını ortaya koydu. ParallelGC her referans atamasında yalnızca üç basit talimatla kart tablosunu güncellerken, G1GC mantığı üç farklı erken çıkış denetimi ve bir yavaş yol barındırıyor. G1GC, nesneyle referansın aynı bölgede olup olmadığını, değerin boş (null) olup olmadığını ve kartın genç bölgede yer alıp almadığını sırayla kontrol ediyor.

İncelemeye göre 16 GB varsayılan yığın boyutunda 8 MB büyüklüğünde bölgeler kullanan G1GC, 1024x1024 elemanlı diziyi başlık ekleriyle birlikte 4 MB eşiğini 16 bayt aştığı için doğrudan devasa (humongous) nesne olarak eski nesil bölgeye ayırdı. Dizi eski bölgede, atanan nesne ise genç nesilde kaldığı için bariyerin üç hızlı çıkışı da başarısız oldu. Sonuç olarak yapılan her bir atama işlemi, donanım düzeyinde tam bellek engeli (dmb ish) içeren yavaş yola yönelerek döngüyü yavaşlattı.

Kaynak

Bu özet yapay zekâ ile hazırlanmıştır; ayrıntılar ve doğrulama için orijinal kaynağa başvurun.