Java finalize ve Garbage Collector

Temizlikİşlemleri : finalize() ve çöp toplayıcı (Garbage Collector)

Yapılandırıcılarsayesinde objelerimiz oluşturulmadan evvel nasıl başlangıç posizyonlarınıverdiğimizi belirtmiştik, peki oluşturulan bu objeler daha sonradan nasılhafızadan silinmektedir . Java dilinde , C++ dilinde olduğu gibi oluşturulanobjelerimizi işleri bitince yok etme özgürlüğü kodu yazan kişinin elindedeğildir. Bir objenin gerçekten çöp olup olmadığına karar veren mekanizma çöp toplayıcısıdır (garbage collector).
Uygulamadabir obje kullanılmıyorsa çöp toplayıcısı(Garbage Collector) tarafındanhafızadan silinir. Bu işlem kodu yazan kişi bakımından büyük bir rahatlıkoluşturmaktadır , çünkü uygulamalardaki en büyük hataların ana kaynağı temizliğin doğru dürüst yapılamamasıdır.

finalize() metodu

finalize()metodunun iki işlevivardır . Birincisi , eğer javada yerel metodlar (native methods) kullanırsak (Java kodu olmayan satırları Java dilinde kullanma ) -ki sonuçta çöptoplayıcısı(Garbage Collector) sadece new ile oluşturulmuş olan objelerihafızan nasıl silineceğini bilmektedir.Javanın içersinde şu an için ikiprogramlama dili desteklenmektedir bunlar C ve C++ dır. Örneğin Javanıniçersinde C diliyle malloc() fonksiyonunu kullanarak hafızada biryer alalım , aynı şekilde alınan bu hafıza alanını geri vermek istersek Cdilindeki free() fonksiyonunu kullanmamız gerekecektir ,işte bu free() fonksiyonunu finalize() metodunun içersine yazarak , alınmış olan hafızaalanı geri verebilmekteyiz.
İkinciişlev olarak , çöp toplayıcı(garbage collector) objeyi hafızadan silmeden hemenönce finalize() metodunu çağırır , aynı idam mahkumunun son isteği gibi finalize()metodunda obje yapması gereken son işlemleri belirtir. Başka birörnek verirsek , bir çizim programı yaptık ve elimizde ekrana çizgi çizen birobjemiz var , bu objemizi hafızadan silmeden evvel ekrana çizdiği çizgilerisilmesini yine finalize() metodunda belirtebiliriz.
Akıllardatutulması gereken diğer bir konu ise eğer uygulamanız çok fazla sayıda çöpobjesi(kullanılmayan obje) üretmiyorsa , çöp toplayıcısı (garbagecollector) devreye girmeyebilir.Bir başka nokta ise eğer System.gc()ile çöp toplayıcısını tetiklemezsek , çöp toplayıcısının ne zaman devreyegirip çöp haline dönüşmüş olan objeleri hafızadan temizleneceği bilinemez.
ör-garbage-collector-1
class Elma {   
 
        int i = 0 ;
 
        Elma(int y) {
               this.i = y ;
               System.out.println("Elma Objesi Olusturuluyor = " + i );             
        }       
 
        public void finalize() {
               System.out.println("Elma Objesi Yok Ediliyor = "+ i );
        } 
}
 
public class Temizle {
 
        public static void main(String args[]) {
               for (int y=0 ; y<10 ;y++) {
                       Elma e = new Elma(y);
               }              
 
               for (int y=10 ; y<21 ;y++) {
                       Elma e = new Elma(y);
               }
        }
 
}
ör-garbage-collector-1 , örneğimizde iki döngü içersindetoplam 21 adet elma objesi oluşturulmaktadır. Kendi bilgisayarımda 256MB RAM bulunmaktadır, böyle bir koşulda çöp toplayıcısı(garbage collector)devreye girmeyecektir ,sebebi ise elma objelerinin java içinayrılan hafıza alanında yeterince yer kaplamamasıdır.Değişik bilgisayarkonfigurasyonlarında örneğin 16 MB RAM bulunan bir makinada , çöp toplayıcısıdevreye girebilir.Uygulamanın çıktısı aşağıdaki gibidir.
Elma Objesi Olusturuluyor = 0
Elma Objesi Olusturuluyor = 1
Elma Objesi Olusturuluyor = 2
Elma Objesi Olusturuluyor = 3
Elma Objesi Olusturuluyor = 4
Elma Objesi Olusturuluyor = 5
Elma Objesi Olusturuluyor = 6
Elma Objesi Olusturuluyor = 7
Elma Objesi Olusturuluyor = 8
Elma Objesi Olusturuluyor = 9
Elma Objesi Olusturuluyor = 10
Elma Objesi Olusturuluyor = 11
Elma Objesi Olusturuluyor = 12
Elma Objesi Olusturuluyor = 13
Elma Objesi Olusturuluyor = 14
Elma Objesi Olusturuluyor = 15
Elma Objesi Olusturuluyor = 16
Elma Objesi Olusturuluyor = 17
Elma Objesi Olusturuluyor = 18
Elma Objesi Olusturuluyor = 19
Elma Objesi Olusturuluyor = 20
Uygulamanınçıktısından anlaşılacağı üzere , Elma objesinin finalize() metodu hiççağrılmadı , sebebi ise çöp toplayıcısının (garbage collector) hiçtetiklenmemiş olmasıdır.
Aynıörneğimizi biraz değiştirelim .

ör-garbage-collector-2
class Elma2 {        
 
               int i = 0 ;
 
               Elma2(int y) {
                               this.i = y ;
                               System.out.println("Elma2 Objesi Olusturuluyor = " + i );                             
               }             
 
               public void finalize() {
                               System.out.println("Elma Objesi Yok Ediliyor = "+ i );
               } 
}
 
public class Temizle2 {
 
               public static void main(String args[]) {
                               for (int y=0 ; y<10 ;y++) {
                                              Elma2 e = new Elma2(y);
                               }
 
                               System.gc() ; // çöp toplayıcısi tetiklendi
 
                               for (int y=10 ; y<21 ;y++) {
                                              Elma2 e = new Elma2(y);
                               }
               }
}

System sınıfının statik bir metodu olan gc(), çöp toplayıcısının , kodu yazan kişi tarafından tetiklenmesi sağlar. Böyleceçöp toplayıcısı çöp haline gelmiş olan objeleri bularak hafızadan siler.
İlk fordöngüsünde oluşturulan Elma objeleri , yine bu for döngüsübitince çöp halini alacaklardır. Bu for döngüsünün içersinde Elmatipinde olan e değişkeni her bir tur yapışında başka bir Elmaobjesine bağlanmaktadır.Böylece bağlanmış olduğu diğer objeler çöphalini alacaktır. En son olarak for döngüsünün bitimiyle Elma tipindeolan e değişkeni kapsama alanına çıkacağından , bu değişkene bağlı olanen son Elma objeside çöp halini alacaktır. Böylece heap bölgesi duran gereksizElma objeleri çöp toplayıcısı tarafından hedef durumuna gelmiştir. System.gc()komutu ile çöp toplayıcısını (garbage collector) tetiklediğimizde , gereksizolan bu on adet Elma objesi hafızadan silinecektir.Bu objeler hafızadansilinirken , finalize() metodunun nasıl çağrıldığını görebiliyoruz.



Hafızadanhangi objeler silinir

Çöptoplayıcısı(Garbage Collector) hafızadan , bir değişkene bağlı olmayanobjeleri siler. Eğer -ki obje bir değişkene bağlı ise , o obje uygulamatarafından kullanılıyordur anlamını çıkartabiliriz. Bir değişkene bağlı olanobjelere çöp toplayıcısı tarafından dokunulmaz.
örnek-cop-obje
public class CopObje {
 
        public static void main(String args[]) {
               Elma e = new Elma(1);
               new Elma(2);
               System.gc() ; // cop toplayıcisini cagirdik 
        }
 
}
Yukarıdakiörneğimizde , 2 adet Elma objesinden biri çöp toplayıcısı(garbagecollector) tarafından hafızadan silinirken , diğer obje hafızada yaşamanısürdürmeye devam eder . Bunun sebebi yapılandırıcısına bir sayısınıgönderdiğimiz objenin , Elma tipindeki e değişkenine bağlıolmasıdır.Uygulamanın çıktısı aşağıdaki gibidir.
Elma Objesi Olusturuluyor = 1
Elma Objesi Olusturuluyor = 2
Elma Objesi Yok Ediliyor = 2
Uygulamamızışekil üzerinde gösterirsek :

Şekil-2

finalize()metodununa güvenirsek neler olur ?

Konubaşlığını bir örnek ile açıklıyalım ;

class Ucak {   
 
        String ucak_isim  ;
        boolean benzin_deposu_dolu = false ;
        boolean benzin_deposu_kapagi_acik_mi = false ;        
 
        Ucak(boolean depoyu_doldur ,String ucak_isim) {
               benzin_deposu_kapagi_acik_mi = true ; // kapagi aciyoruz
               benzin_deposu_dolu = depoyu_doldur ;//depo full
               this.ucak_isim =ucak_isim ;
        }       
 
        public void finalize() {
 
               if (benzin_deposu_kapagi_acik_mi) {  // kapak aciksa
                       benzin_deposu_kapagi_acik_mi = false ;// kapagi kapa
                       System.out.println(ucak_isim + " - kapaklari kapatildi ");
               }
        } 
}
 
public class BenzinDepo {
 
        public static void main(String args[]) {                     
 
            Ucak ucak_1 = new Ucak(true,"F-16"); // benzin doldur
            new Ucak(true,"F-14");  //benzin doldur
            System.gc();//kapaklari kapat
            System.out.println("Ucaklara benzin dolduruldu,kapaklari kapatildi");
        }
}
Buörneğimizde iki adet Ucak objeyi oluşturuyoruz , objelerimizi oluştururoluşturmaz , kapaklarını açıp depolara benzinleri doldurmaktayız . Kapaklarıkapatma işlemi için finalize() metodunu kullanıyoruz. Sonuçta System.gc()çağrılınca çöp toplayıcısının (garbage collector) tetiklendiğinibilmekteyiz .Uygulamanın çıktısı :
F-14 - kapaklari kapatildi
Ucaklara benzin dolduruldu,kapaklari kapatildi
Uygulamaçıktısının gösterdiği gibi , sadece F-14 Ucak objesinin benzin deposununkapağı kapatılmış durumda , F-16 Ucak objesinin ise kapağı halaaçık durmaktadır. Bu yanlışlığın sebebi , F-16 Ucak objesine Ucaktipinde olan ucak_1 değişkenin bağlanmış olmasıdır . Çöptoplayıcısı (garbage collector) boşta olan objeleri hafızadan temizler , yaniherhangi bir objeye bir değişken bağlanmamış ise o obje boşta demektir.Bu örneğimizde boşta olan obje F-14 Ucak objedir ve çöp toplayıcısıtarafından temizlenmiştir.
Özet olarak, System.gc() ile çöp toplayıcısını(garbage collector) tetikliyebilirizama değişkenler objelere bağlandığı sürece , bu objelerinhafızadan atılması söz konusu değildir.Bu sebepten dolayı finalize() metodunukullanırken dikkatli olmalıyız.

Çöptoplayıcısı (Garbage Collector) nasıl çalışır ?

Çöptoplayıcısının temel görevi , kullanılmayan objeleri bulurak bunları hafızadansilmektir.Sun Microsystems tarafından tanıtılan Java HotSpot VM (VirtualMachine)sayesinde heap bölgesindeki objeler nesillerine göre ayrılmaktadır. Bunesiller eski nesil ve yeni nesil objeler olmak üzere ikiçeşittir.Belli başlı parametreler kullanarak Java HotSpot VM mekanizmasınıkontrol etmeniz mümkündür . Java HotSpot VM bizlere sağlandığı hazırparametreler ile normal bir uygulama gayet performanslı çalışabilir.Eğersunucu(server-side) üzerinde uygulamalar geliştiriyorsanız , Java HotSpot VMparametrelerini doğru kullanarak uygulamanızın performasını bulunduğu yerdendaha yükseklere çıkartmanız mümkündür.
Dahaevvelden söz ettiğimiz gibi , objelerin hafızadan silinmesi görevi kodu yazankişiye ait değildir.Bu işlem tamamen çöp toplayıcısının sorumluluğundadır.JavaHotSpot VM 1.3.1 ait çöp toplayıcısı iki konuyu kullanıcılara garanti etmektedir.
· Kullanılmayanobjelerin kesinlikle hafızadan silinmesi sağlamak.
· Objehafıza alanının parçalanmasını engellemek , ve hafızanın sıkıştırılmasısağlamak.
Bubölümde dört adet çöp toplama algoritmasından bahsedeceğim , bunlardanilki ve ilkel olanı referans sayma yöntemidir , bu yöntem modernJVM (Java Virtual Machine) ler tarafından kullanılmaz .

Eskiyöntem

ReferansSayma Yöntemi
Buyöntemde , bir obje oluşturulur oluşturulmaz kendisine ait bir sayaç çalışmayabaşlar ve bu sayacın ilk değeri birdir , bu objemizin ismi X olsun.Busayaç'ın saydığı şey,oluşturduğumuz objenin kaç adet değişkenebağlı olduğudur.Ne zaman yeni bir değişken bu X objesine bağlansa, busayac bir artar , aynı şekilde ne zaman bu X objesine bağlı olan bir değişken geçerlilikalanı dışına çıksa veya değişkenin içinde bulunduğu başka bir obje çöptoplayıcısı tarafından hafızadan silinse , X objesine ait bu sayaç bireksilir.Eğer sayaç sıfır değerini gösterirse X objemiz çöptoplayıcısı tarafından hafızadan silinir.
Buyöntem , kısa zaman aralıkları ile çalıştırıldağında iyi sonuçlar vermektedirve gerçek zamanlı uygulamalar için uygun olduğu söylenebilir. Fakat bu yönteminkötü yanı döngüsel ilişkilerde referans sayacının doğru değerlergöstermemesidir.Örneğin iki objemiz olsun , bunlardan biri ana obje diğeri iseçocuk objesi olsun(ana obje - cocuk obje terimlerini kalıtım konusundainceliyeceğiz). Eğer ana obje , çocuk objeye , çocuk objede ana objeyi döngüselbir biçimde bağlanmış ise , bu objeler artık kullanılmıyor olsa dahi ,sayaçları hiç bir zaman sıfır olmaz ve bu yüzden çöp toplayıcısı tarafındanhafızadan silinmezler.

YeniYöntemler

Toplamüç adet yeni çöp toplayıcısı yönetimi mevcuttur.Bu üç yönteminde ,yaşayanobjeleri bulma stratejisi aynıdır. Bu strateji , hafıza içinde yer alan ,statikve stackalanlarındaki değişkenlerin bağlı bulunduğu objeler aranılarak bulunur.Eğer birdeğişken (referans) bir objeye bağlıysa , bu obje uygulama tarafındankullanılıyor demektir yani canlı objedir.
Kopyalamayöntemi
Oluşturulanbir obje heap bölgesindeki yeni nesil alanında yerini alır , eğerbu obje zaman içinde çöp toplayıcısı tarafından silinmemiş ise belli birolgunluğa ulaşmış demektir ve heap bölgesindeki eski nesil alanına geçmeye hakkazanır.Yeni nesil bölgeleri arasında kopyalanma işlemi ve bu alandan ,eski nesil alana kopyalanma işlemi , kopyalama yöntemi sayesindegerçekleşir.
İşaretleve süpür yöntemi
Zamaniçinde objeler belli bir olgunluğa erişince heap bölgesindeki eski nesilalanına taşındıklarını belirtmiştik. Eski nesil alanındaki objeleri hafızadansilmek ve bu alanındaki paçalanmaları engellemek için işaretle ve süpüryöntemi kullanılır. İşaretle ve süpür yöntemi , kopyalama yöntemine göre dahayavaş çalışmaktadır.
Artan(sıra) yöntem
Kopyalamayöntemi veya işaretleve süpür yöntemi ,uygulamanın üretmiş olduğu büyük objeleri hafızadansilerken kullanıcı tarafından farkedilebilir bir duraksama oluştururlar. Bufarkedilir duraksamaları ortadan kaldırmak için Java HotSpot Vm artanyönetimini geliştirmiştir.
Artanyöntem , büyük objelerin hafızadan silinmesi için orta nesil alanıoluşturur , bu alan içerisinde küçük küçük bir çok bölüm vardır ,bu sayede büyük objeleri hafızadan silerken oluşan farkedilirduraksamalar , küçük ve farkedilmez duraksamalara dönüştürülmektedir.
Artanyönetemi devreye sokmak için -Xincgc , devreden çıkartmak için ise-Xnoincgc parametreleri kullanılır. Java HotSpot Vm normalşartlarda bu yöntemi kullanmaz eğer kullanılmasını istiyosak bu işlemikendimiz yapmak zorundayız.
gösterim-5
java -Xincgc BenzinDepo

Heapbölgesi

JavaHotSpot VM (Virtual Machine), heap bölgesini nesillere göre yönetir. Hafızaalanında değişik nesillerdeki objeler bulunur. Aşağıdaki şeklimizde heapbölgesinin nesillere göre nasıl ayrıldığını görebiliriz.

Şekil-3
Kalıcıalan özel bir bölgedir (32 MB dan 64 MB kadar yer kaplayabilir). Bu bölgedeJVM'e ait bilgiler bulunur. -XX:MaxPermSize=64m komutu ile , bu alanınboyutlarını kontrol edebiliriz.

YeniNesil

YeniNesil toplam 3 alandan oluşur , başlangıç alanı , ve iki adet boş alan(ba#1 ve ba#2) . Bu iki boş alandan bir tanesi bir sonraki kopyalama (kopyalamayöntemi çalışır)için her zaman için boş tutulur. Başlangıç alanındaki objelerbelli bir olgunluğa ulaştıkları zaman boş olan alanlara kopyalanırlar.

EskiNesil

Eskinesil objeler heap alanındaki eski alanında bulunurlar. Uygulamatarafından kullanılan uzun ömürlü objeler yeni nesil alanından , eski nesilalanına taşınırlar.Bu objeler eski nesil alanında biriktikçe hafıza alanındayetersizlik ortaya çıkabilir , bu esnada işaretle ve süpüryöntemi devreyegirer.

Heapbölgesinin boyutlarını nasıl kontrol edilir.

Heapbölgesine minimum veya maksimum değerleri vermek için -Xms veya -Xmxparametlerini kullanırız. Performansı arttırmak amacı ile genişkapsamlı sunucu (server-side) uygulamalarında minimum ve maksimum değerlerbirbirlerine eşitlenerek sabit boyutlu heap bölgesi elde edilir.
JVMherhangi bir çöp toplama yöntemini çağırdıktan sonra , heap bölgesini, boşalanlar ile yaşayan objeler arasındaki farkı ayarlamak için büyütür veyaazaltır.Bu oranı yüzdesel olarak minimum veya maksimum değerler atamakistiyorsak -Xminf veya -Xmaxf parametreleri kullanılabilir.Budeğer (SPARC Platform versiyonu) için hali hazırda minimum %40 ,maksimum %70 dır.
gösterim-6
java -Xms32mb Temizle 
gösterim-7
java -Xminf%30 Temizle
Heapbölgesinin JVM tarafından büyütülüp küçültüldükçe , eski nesil ve yeninesil alanlarıda NewRatio parametresine göre yineden hesaplanır. NewRatioparametresi eski nesil alan ile yeni nesil alan arasındaki oranı belirlemeyeyarar. Örneğin -XX:NewRatio=3 parametresinin anlamı eski nin yeniyeoranının 3:1 olması anlamına gelir, yani eski nesil alanı heap bölgesinin 3/4 ,yeni nesil ise 1/3 yer kaplayacakdır. bu şartlarda kopyalama yöntemidaha sık çalışması beklenir. Eğer ki eski nesil alanı daha küçük yaparsak ozaman işaretle ve süpür yöntemi daha sık çalışacakdır. Daha evveldenbelirtildiği gibi işaretle ve süpür yöntemi , kopyalama yönteminegöre daha yavaş çalışmaktadır.
gösterim-8
java -XX:NewRatio=8 Temizle
NewSize ve MaxNewSize parametreleri ,yeni nesil alanının minimum ve maksimum değerlerini belirmek içinkullanılır.Eğer bu parametleri birbirlerine eşitlersek , sabit uzunlukta yeninesil alanı elde etmiş oluruz.Aşağıdaki gösterimde yeni nesil alanlanın 32MBolucağı belirtilmiştir.
gösterim-9
java -XX:MaxNewSize=32m Temizle

Kopyalamayönteminin gösterimi

Aşağıdakişeklimizde , yaşayan objeler kırmızı renk ile ifade edilmişlerdir.

Şekil-4
Objelerimizbelli bir olgunluğa ulaşıncaya kadar yeni nesil alanının bölümleri arasında pasedililer.Bu esnada uygulanan yöntem kopyalama yöntemidir. Bellibir olgunluğa ulaşan objelerimiz en son aşamada eski alana gönderilirler.

İşaretleve süpür yönteminin gösterimi

iyitasarlanmış bir sistemde , çöp toplayıcısının bir kaç defa devreye girmesiyleile birlikte çoğu objenin ölmesi gerekir , geriye kalan yaşayan objeler iseeski nesil alanına geçmeye hak kazanırlar.Eski nesil alanında işaretle vesüpür yöntemi kullanılır , bu yöntem kopyalama yöntemine göre dahayavaş fakat daha etkilidir.

Şekil-5
Aşağıdakiörneğimizde , ne zaman kopyala yönteminin çalıştığını , ne zaman işaretleve süpür yönteminin çalıştığını gösterilmektedir.
ör-heap-gosterim
public class HeapGosterim {
 
        public static void main(String args[]) {
               for (int y=0 ; y<100000 ;y++) {
                       new String("Yer Kaplamak icin");
                       new String("Yer Kaplamak icin");
                       new String("Yer Kaplamak icin");
                       if ( (y%10000) == 0 ) { 
                           System.gc();
                       }
               }
        }
}
Buörneğimizde 3 adet String objesi her döngüde oluşturularak hafızadan yeralınmaktadır.Bu objelerimize herhangi bir değişken bağlanmadığından ,çöp toplayıcısının herhangi bir zamanda devreye girmesiyle hafızdan silineceklerdir.Eğeruygulamamızı aşağıdaki formatta çalıştırsak gerçekleşen olayları daha iyianlayabiliriz.
gösterim-10

java -verbosegc HeapGosterim

Uygulamanınçıktısı aşağıdaki gibidir.


Yorumlar

Bu blogdaki popüler yayınlar

Soru ve Cevaplarla Kompanzasyon

Aktif Güç Nedir,Reaktif Güç Nedir

Sinusoidal AC dalga şekli, Tepe, ortalama, efektif(rms), değer tanımları...