Merhaba bugün sizlere Java’nın en önemli özelliklerinden birisi olan Garbage Collector’un nasıl çalıştığından bahsedeceğim.
Garbage Collector heap alanında çalışan ve heap alanında new operatörü, Class.forName().newInstance(), clone() veya readObject() metotlarıyla oluşturulan ve referansı olmayan nesneleri heap alanından temizleyen mekanizmanın adıdır.
Java programlama diliyle uygulama geliştiren birçok geliştiricinin temel seviyede haberdar olduğu Garbage Collector’ı inceleyeceğiz. C, C++ dillerinde geliştiriciler kullandıkları nesnenin işi bittikten sonra onu hafızadan kendileri silmek zorundaydılar. (alloc(), dealloc() veya free()) Java programlama dili geliştirilirken C, C++ gibi dillerin güçlü yönleri alınmıştır fakat hafıza yönetimi için GC kullanılmıştır.
Heap Hafıza alanı içerisinde JVM ve GC’nin çalıştığı alanlar aşağıdaki gibidir.
Kalıcı Alan: Bu bölgede JVM ait özel bilgiler bulunur. Örneğin: -XMaxPermSize=64MB komutuyula alanın büyüklüğü belirtilir.
Yeni Nesil Alanı: Bu bölüm toplam üç alandan oluşur. (BA#1, BA#2, Başlangıç Alanı) Oluşturulan nesneler ilk olarak Başlangıç alanında bulunurlar. Belirli bir olgunluğa eriştikten sonra BA#1 veya BA#2 alanlarından boş olana kopyalanır. BA#1 veya BA#2 alanlarından birisi bir sonraki kopyalama için her zaman boş tutulur.
Eski Nesil Alanı: Bu bölümde eski nesil nesneler tutulur. Uygulamanın kullandığı uzun ömürlü nesneler yeni alanından bu alana taşınırlar. Eski nesil alanından biriken nesneleri silmek için işaretle ve süpür algoritması kullanılır.
Garbage Collector işlemini 3 adımda tamamlar. Bunlar:
- İşaretle: Kullanılan ve kullanılmayan nesneler işaretlenir.
- Silme: Referansı olmayan nesneleri heap alanından temizler.
- Sıkıştırma ve Silme: Silme işlemine ek olarak daha büyük nesnelere boş alan oluşturmak için kalan nesneleri bir araya getirir.
Garbage collector’ın heap alanını temizleme işlemi için kullandığı algoritmalar aşağıdaki gibidir.
1. Referans Sayma Yöntemi: Bu yöntem eski bir GC algoritmasıdır. Aktif olarak kullanılmamaktadır. Bir nesne oluşturalım ve bu nesnenin adı X olsun. X nesnesi ilk oluşturulduğunda bu nesneye ait bir sayaç oluşturulur ve ilk değer olarak bir atanır. X nesnesine yeni bir referans bağlandığında sayacın değeri bir arttırılır. X nesnesine bağlı olan bir referans geçerlilik alanı dışında kaldığında veya X nesnesine null atandığında sayacın değeri bir eksiltilir. Eğer sayacın değeri sıfırı gösterirse X nesnesi heap alanından silinir.
Bu yöntemin kötü yanı döngüsel ilişkilerde referans sayacının doğru değeri göstermemesidir. Örneğin X ve Y olarak iki tane nesnemiz var. X nesnesi referans olarak Y nesnesini göstersin ve Y nesnesi de referans olarak X nesnesini göstersin. Bu durumda referans sayaçları hiç bir zaman sıfır değerini gösteremeyeceği için bu iki nesne kullanılmasa GC bu nesneleri bellekten silmeyecektir.
2. Kopyalama Yöntemi: Oluşturulan bir nesne ilk olarak heap bölgesindeki yeni nesil alanında yerini alır. Eğer nesne zaman içerisinde GC tarafından silinmemiş olursa nesne belirli bir olgunluğa ulaşmış demektir. Bu durumda nesne Yeni Nesil Alanından Eski Nesil Alanına taşınır.
3. İşaretle ve Süpür: Nesneler belirli bir olgunluğa erişince Eski Nesil Alanına taşınmışlardı. Eski Nesil Alanında biriken ve kullanılmayan nesneleri silmek ve bu alandaki parçalanmaları engellemek için işaretle ve süpür yöntemi kullanılır. Bu yöntem kopyalama yöntemine göre daha yavaş çalışır.
4. Artan (Sıra) Yöntemi: Kopyalama, İşaretle ve Süpür yöntemi uygulamanın oluşturmuş olduğu büyük nesneleri silerken kullanıcı silme işlemi esnasında oluşan duraksamaları fark edebilir. Bunu engellemek Orta Nesil Alanı oluşturulur. Bu alan küçük küçük bölümlerden oluşur. Kısaca büyük nesneler küçük bölümler haline getirilir ve bellekten silinir. Bu yöntemle, GC büyük nesneleri silerken kullanıcı duraksamaları fark etmeyecektir. Bu yöntemi JVM’de aktif hale getirmek için -Xincgc pasif hale getirmek için -Xnoincgc komutları kullanılır.
Garbage collector’ın 3 farklı şekilde çalışır. Bunlar:
1. Minor GC: Nesneler ilk olarak başlangıç alanında oluşturulmuştu. Bu alan dolduğunda Minor GC devreye girer ve belirli olgunluğa ulaşan nesneleri BA#1 veya BA#2 alanlarından boş olanına taşır ve kullanılmayan nesneleri başlangıç alanından temizler. Örneğin BA#1 boş alan olsun. Başlangıç alanında ve BA#2 alanında yaşayan nesnelerin tamamı BA#1 alanına taşınır. Bir sonraki Minor GC’de Başlangıç alanındaki ve BA#1 alanındaki yaşayan nesneler BA#2 alanına taşınırlar. Nesnelerin BA#1 ve BA#2 alanları arasında taşınma sayıları sayılır. Eğer nesnelerin taşınma sayıları belirli eşik değeri sayısını geçtiyse nesneler belirli bir olgunluğa erişmiş olurlar ve Eski Nesil Alanına taşınırlar. Minor GC sonucunda Başlangıç alanı tertemiz ve BA#1 veya BA#2 alanlarından birisi tertemiz diğeri ise canlı kalan tüm nesneleri barındırır. Minor GC Stop the World çalışır fakat çok hızlı olduğu için sürenin bir önemi kalmaz. Bu yüzden yaygın olarak Minor GC nin Stop the World olarak çalışmadığı düşünülür.
2. Major GC: Eski nesil alanında çalışır ve eski nesil nesneleri temizler. Minor GC ye göre yavaştır. Major GC genellikle Minor GC’den sonra tetiklendiği için Full GC olarak algılanır. Major GC Stop the World çalışır.
3. Full GC: Tüm heap alanında çalışır ve kullanılmayan tüm nesneleri heap alanından temizler. Full GC Stop the World çalışır. Kodlama içerisinde Full GC çalıştırmak için System.gc(); çağırmanız yeterli olacaktır.
Farklı sistemler için optimize edilen Garbage Collector tipleri aşağıdaki gibidir.
- Serial GC: Java 5 ve 6’da varsayılan olarak kullanılan bir GC tipidir.
- Minor ve Major GC için işaretle ve süpür algoritmasını kullanır.
- Minor ve Major GC seri olarak işler.
- Aktifleştirmek için: -XX:+UserSerialGC komutu kullanılır.
- Parallel GC:
- Yeni Nesil alanında GC çalıştırmak için multiple thread kullanır.
- Eski nesil alanında çalışırken de multiple thread kullanır.
- Yeni Nesil Alanında çalışmasını aktifleştirmek için: -XX:+UseParallelGC komutu kullanılır.
- Hem Yeni Nesil hem Eski Nesil alanlarında aktifleştirmek için: -XX:+UseParallelOldGC komutu kullanılır.
- Concurrent Mark Swep(CMS):
- Boşalan alanları geri alır.
- GC stop the world durdurma işlemini en aza indirmeye çalışır.
- Yaşayan nesneleri başka bir alana taşımaz ve sıkıştırmaz.
- Yeni nesil alanında GC algoritması Parallel GC ile aynıdır.
- Aktif hale getirmek için: -XX:+UseConcMarkSweepGC ve thread sayısını ayarlamak için -XX:ParallelCMSThreads=<n> komutları kullanılır.
- G1 (Garbage First) GC:
- Java 7 ile birlikte gelmiştir ve CMS algoritmasının yerine kullanılacaktır.
- Genellikle büyük heap (4GB) alanlarına sahip uygulamalar için kullanılır.
- Heap alanını bölge bölge ayırır ve paralel olarak toplar.
- Yüksek performans için tasarlanmıştır ve 1 saniyenin altında temizlik işlemini bitirir.
- Çalışırken artırımsal sıkıştırma işlemini yapar.
- Aktif hale getirmek için -XX:+UseG1GC komutu kullanılır.
Yılın son yazısı olması adına System.gc(2017);
İyi yıllar iyi çalışmalar. 🙂