Java Garbage Collection Part1

Kerim Fırat
5 min readJul 5, 2021

Bugüne kadar işlediğimiz Java ile ilgili makalelerde zaman zaman çöp toplama sistemine değindik. Ve bu sistemi oluşturanın GC(Garbage Collection) olduğunu biliyoruz. Dolayısıyla bu yazı serisinde GC’nin çalışma mimarisini inceleyeceğiz.

Otomatik GC Nedir?

Java’da çöp toplama sisteminin farklı durumlarda devreye girdiğini-girebileceğini biliyoruz.Bu durumlardan en temeli “otomatik gc”’dir. Yani developer’in bu konuda bir rolü yoktur.

Otomatik çöp toplama sistemi heap bellek bölgesini sürekli kontrol eden bir işlem sürecidir. Ve gerektiğinde temizleme işlemini yapma insiyatifine sahiptir. Aslında GC tüm durumlarda kendi insiyatifini kullanır. Developer ancak bu sürece küçük de olsa bir katkı yapabilir. Bu katkı yöntemlerine “Java Virtual Machine(JVM) Parameters” yazılarında bahsetmiştim.

Kullanımda olan bir nesne veya başvurulan bir nesne,programınızın bir bölümünün hala o nesneye bir işaretçi(pointer) tuttuğu anlamına gelir. Ancak kullanılmayan bir nesne veya referans verilmeyen bir nesneye,artık programınızın herhangi bir bölümü tarafından kullanılmadığı anlamına gelir.
Ancak bu hale gelmiş bir nesne bellekte yer kaplamaya devam eder.Dolayısıyla bellek tüketimi artar ve hem bellek tüketiminin artmaması,hem de boşa duran bu bellek alanının kullanabilir hale getirilmesi gerekir.

C dilinde bellek ayırma ve belleği serbest bırakma(tekrar kullanıma kazandırmak) işlemi manuel olarak,yani developer tarafından yapılır ve kesin olarak developer sorumluluğundadır.
C’de bir işlem için bellek ayırma:

int *ptr = (int*)malloc(20 * sizeof(int));

C’de bellek alanını serbest bırakma developer sorumluluğundadır:

free(ptr);

Java’da bellek ayırma:

Object obj = new Object();

Java’da bellek serbest bırakma:
GC sorumluluğundadır.

Java’da bu işlem GC tarafından otomatik olarak gerçekleştirilir. Ve bu otomatik süreç bazı aşama biçimleri barındırır.
Çünkü kullanılan,kullanılmayan vb. bellek alanının doğru tespit edilmesi gerekir. Aksi halde istenmeyen problemlere yol açacaktır. Otomatik GC’nin barındırdığı aşamamaları sırasıyla aşağıda inceleyeceğiz.

Marking(İşaretleme)

GC’nin ilk ve en temel aşamasıdır.Bu aşamada kullanımda ve kullanımda olmayan bellek paçalarının-bölümlerin işaretlendiği yerdir.Aşağıdaki görselde “marking” aşaması gösteriliyor.

oracle.com

Görselde programınızın kullandığı bellek alanları görülmektedir. Görseldeki başvurulan-kullanılan alanlar mavi olarak gösteriliyor. Başvurulmayan,yani artık kullanılmayan nesneler ise sarı renkle gösteriliyor. Bu belirlemenin yapılabilmesi için programınıza ait tüm nesneler işaretleme aşamasına tabi tutulur,yani bu aşamada taranır. Ancak programınız tarafından oluşturulan tüm nesnelerin taranması zaman alan bir süreç olabilir.Yine bununla ilgili bazı ince ayarlar yapılabilir(bknz:”Java Virtual Machine(JVM) Parameters”).

Normal Deletion(Silme)

Bu silme işlemi GC’nin ikinci aşaması ve silme biçimlerinden biridir.Bu silme işlemi biçimi,referans verilmeyen nesneleri kaldırır-siler. Aşağıdaki görselde normal silme işlemi gösteriliyor.

oracle.com

Görseli incelediğimizde sarı renkler,yani kullanılmayan alanların temizlendiği görülüyor.Ve temizlenen alanların adresleri gerektiğinde tekrar kullanılması için bir liste olarak “Bellek Ayırma” işlemini yapan “Memory Allocator(Bellek Ayırıcı)”’a teslim edilir. Ancak bu işlemden sonra pek de kullanışlı olmayan bir durum ortaya çıkıyor. Her ne kadar boş bellek alanların listesini teslim etmiş olsa da,boş alanlar çeşitli boyutlardadır. Dolayısıyla tekrar kullanım için pek verimli değildir. Sebebi ise: Bellek ihtiyacı doğduğunda bu ihtiyacın boyutu bellidir ve dolayısıyla bu boyuta uygun bir alan ayrılmalıdır. İhtiyaç duyulan bu bellek boyutu liste içindeki alanların boyutları arasından aranır.
Boyuta uygun bir alan bulunursa oraya yerleştirilir. Bu süreçte ihtiyaç duyulan bellek boyutu liste içindeki alanların boyutlarından küçük olabilir. Böyle bir durumda ilgili boş alan tekrar bölünür. Bu bölünmeler dağınık ve çeşitli boyutlarda olacağı için tekrar kullanıma uygunluk durumu düşer ve tamamen kullanışsız bir duruma gelebilir.Bu da kötü bir bellek yönetim biçimidir.

Deletion with Compacting(Sıkıştırarak Silme)

Bu silme işlemi GC’nin ikinci silme biçimidir. Bu biçiminde yine ilki gibi silme işlemi gerçekleştirir ve aynı zamanda sıkılaştırma işlemi uygular. Yani silme işlemi sonrasında boş kalan bellek alanlarını sıkılaştırır. Daha açık ifadeyle söylersek,kullanılan alanları kaydırarak alanları birbirine yakınlaştırır. Böylece aralarında boşluk kalmaz ve normal silme işmeline göre daha iyi bir bellek yönetimi sağlar. Aşağıdaki görselde bu işlemin sonucu görülüyor.

oracle.com

Ancak tüm nesneleri taramak,işaretlemek ve sıkılaştırmak en iyi çözüm değildir. Daha fazla nesne tahsis edildikçe nesnelerin listesi büyür. Bu da daha uzun tarama,işaretleme ve dolayısıyla uzun çöp toplama süresine yol açar.

Generations GC

Bu bölümde işaretleme ve silme işleminin optimize edilmiş versiyonunu inceleyeceğiz.Bu versiyon mevcut kullanılan versiyondur ve oldukça verimlidir. Bu versiyonda kullanılacak bellek alanlar farklı jenerasyonlara(nesillere) bölünür. Aşağıda bu veriyonun modeli gösterilmektedir.

oracle.com

Görseldeki modeli incelediğimizde “Young Generation(Genç jenerasyon)”,”Old Generation(Eski jenerasyon)” ve “Permanent Generation(Kalıcı jenerasyon)” olarak üç ana bölüm görüyoruz. Ve “Young Generation” bölümünde ise üç adet alt bölüm “Eden,S0,S1” yer alıyor. Modelin bölümlerini sırasıyla inceleyelim.

  • Young Generation:
    “Eden” alanı yeni nesnelerin yaratıldığı yerdir.Dolayısıyla en genç nesneler burda yer alır.Bu alan belli bir yüzdeliğe kadar doldurulduğunda GC yapılır. Bu olaya “Minor GC” denir. GC’den sonra “Eden” alanında hayatta kalan nesneler “S0” ve “S1” alanlarına taşınır. Minor GC “Young” bölümünde oldukça aktiftir ve her alt bölüm üzerinde gerçekleşir.Aynı şekilde S0'da Minor GC gerçekleşir ve hayatta kalan nesneler sırasıyla bir sonraki alan olan S1'e taşır.Yani nesne yaşlandıkça bir sonraki alana taşır. Dolayısıyla taşıma işlemi “Eden” -> “S0” -> “S1” şeklinde ilerler.
  • Old Generation:
    Bu bölümde uzun süre hayatta kalan nesneler tutulur.Tipik olarak “Young” bölümü için bir eşik belirlenmiştir ve bu eşiğe ulaşan nesneler “Old” bölümüne taşınır.Dolayısıyla “Young” bölümünde birden fazla Minor GC işleminden kurtulan nesneler “Old” bölümüne taşınır. Yani S1'den sonra “Old Generation” alanına taşınır.Bu bölüm dolduğunda kullanılmayan nesneleri temizlemek için Main GC(veya Major GC denilebilir) gerçekleşir.Bu olay uygulamanın çalışmasında küçük bir duraklamaya neden olabilir.Çok fazla sık kullanılan Main GC ,uygulamada performans sorununa neden olabilir.
  • Permanent Generation:
    Bu bölüm class’ların meta verilerini içerir. Yani class’ların isimleri,methodları vb. bu bölümde yer alır. JVM buradaki bilgilerin gerekli olmadığını tespit ederse,bu bölümü de GC’ye dahil eder.

Devamı: “Java Garbage Collection Part2” yazımda “Generation GC”’nin detayları-çalışma mimarisi işlenecektir.

KAYNAKLAR:
https://www.oracle.com
https://openjdk.java.net/

-end of

--

--

Kerim Fırat
Kerim Fırat

Written by Kerim Fırat

Senior Android Platform(AOSP,AAOS) Architect,Open Source Contributor | Turkey Java User Group Vice Chairman | Author

No responses yet