in Java

Heap Dump nedir?

Heap Dump’ı açıklamak için öncelikle Heap nedir onu bilmek lazım.

Herhangi bir Java sınıfından new operatörü ile bir nesne oluşturulduğunda, bu nesnenin bilgisayarın hafızasında konuşlandırıldığı alana Java Heap adı verilir. Bu heap alanı ise JVM kontrolündedir. Bildiğimiz gibi Java kodlarının çalıştırılabilmesi isin Java Virtual Machine kısaca JVM’e ihtiyacımız var. JVM bizim için heap alanını oluşturur ve Garbage Collector aracılığı ile kontrolünü sağlar.

Peki Heap Dump nedir?

Heap Dump, heap bölgesinin bir kopyasını bizim için çıktı olarak alma işlemidir. Bu dosyadan heap’te ne kadar nesne yaşıyor,bellek ne kadar kullanılıyor gibi sorulara gerekirse saniye saniye cevap bulabiliyoruz. Yani kısaca bellekte ne var ne yok öğrenebiliyoruz.

Güzel öğrendik ama neden böyle birşeye ihtiyaç duyalım ki?

Daha ortada Java yokken nesnelerden bir diğer deyişle bellek tahsis edilen her bir değişkenden programcılar sorumluydu. Fakat Java ile gelen Garbage Collector bizi bu yükten kurtardı. Bizim yerimize bellekte kullanılmayan nesneler otomatik olarak kaldırıyor.Fakat, Her ne kadar Java programcılarının karşılaşmak istemediği bir hata olsa da kimi zaman java.lang.OutOfMemoryError hatasıyla da karşılaşabiliriz. Bu hata bize JVM tarafından oluşturulan Heap bölgesinin dolduğunu haber veriyor. Böyle bir durumla karşılaştığımızda sorunu görebilmek ve çözebilmek için Heap bölgesinin bir çıktısını alıp incelememiz gerekiyor.

Garbage Collector kullanılmayan nesneleri kontrol edip silmiyor muydu? Neden dolabilir ki bu bellek?

Bunun en basit iki nedeni olabilir.İlki JVM tarafından ayrılan bellek boyutunu küçük ayarlamış olabilirsiniz.Bu sorun için bellek boyutunu arttırabilirsiniz.

Eclipse için anlatmak gerekirse Run -> Run Configurations -> Arguments -> VM Arguments kısmına JVM için bellek boyutunu belirteceğiniz argümanları yazabilirsiniz.Örnek olarak;

-Xmx256m

Bellek miktarını 256 MB olarak ayarlayacaktır.

-Xms64m -Xmx512m

JVM başlangıçta bellek miktarını 64 MB olarak ayarlayacaktır. Bu rakamı aşan bir ihtiyaç olduğunda ise 512 MB’a yükseltecektir.

İkinci neden ise kullandığınız nesneleri işiniz bitince bellekten kaldırılması için referanssız bırakmamanızdır. Ne demek bu açıklayalım.

Örneğin;Bir Map veri yapısı kullandığımızı varsayalım. Devamlı nesne oluşturup eklediğimizi ama kullandıktan sonra da o veriyi silmediğimizi düşünelim. Böyle bir durumda kullanılmayan nesneler heap bölgesinde yaşamaya devam eder. Çünkü hala o Map veri yapısı aracılığıyla erişilebilir durumdadır.Dolayısıyla bir referansı vardır.Map veri yapısından o nesneyi çıkarmamız o nesneyi referanssız kılar.Bu durumda ise Garbage Collector o sahipsiz nesneyi uçurur. Böyle bir durumda eğer Map ile de işimiz bittiyse o referansı null olarak eşitlemekte, o Map’in içindeki bütün nesnelerin heap bölgesinden silinmesini sağlar. Kısaca kullanımı biten nesnelerin referanslarını kaldırıyoruz.Garbage Collector bizim için ortalığı temizliyor.

Heap Dump yapmadan da bellekteki boş alanı aşağıdaki kod ile öğrenebiliriz.Bu sayede yukarıda belirtmiş olduğum parametreleri kullanarak ihtiyaca göre belleği ayarlayabilirsiniz.

Heap Dump’ı inceleyip çözüm üretmek

Artık neden bu hatayı aldığımızı biliyoruz.Dolayısıyla Heap Dump sonucunu inceleyerek hangi nesnelerin belleği şişirdiğini görebilir ve bu doğrultuda kodumuzu kontrol edebiliriz. Gerektiği yerde nesneleri referanssız bırakırız ve sorun çözülür.

 

Yorum yaz

Comment

  1. Merhabalar Hocam,

    yazi icin ilk önce cok tesekkür ederim. Bir solukta okudum.
    Fakat birsey kafama takildi, oda son cümle: “Gerektiği yerde nesneleri referanssız bırakırız ve sorun çözülür.” demissiniz. Bir örnek verebilir misiniz? Nesneyi nasil referansiz birakabilirim?

    Tesekkürler
    Erkan Kaplan

    • Merhaba Erkan,
      Yorumun için ben teşekkür ederim.
      Sorunu örnekle cevaplayayım. Diyelim ki bir nesne oluşturmak istiyorsun. Java dilinde nesne oluşturmak için yazman gereken kod şu şekildedir:
      new Foo();
      Foo sınıfından bir nesne üretmiş olduk. Ancak şu anda bir referans değeri yok. Referans değeri olmazsa daha sonradan bu nesneye erişim sağlayamayız. Erişim sağlanamayacak bir nesneyi de Garbage Collector silinecek bir nesne olarak görür. Genellikle nesneyi tekrar kullanacağımız için bir referansa atarız. Yani örnekle gösterecek olursak;
      Foo fooObject = new Foo();
      Artık fooObject adındaki referans ile oluşturduğumuz nesneye ulaşabiliyoruz. Şimdi nesneyi kullandık ve artık işimiz kalmadı. Senaryoya göre de bayağı da yer kaplıyor. Eğer şöyle yaparsak nesnemiz referansını kaybeder:
      fooObject = null;
      Artık elimizde o nesneye ulaşabileceğimiz bir referansımız kalmadığı için de Garbage Collector bakar ki bu nesne sahipsiz öylece bellekte duruyor. Alır götürür.
      Umarım anlatabilmişimdir.

      • peki uğurcan fooObject local değişken değil mi ?
        (ben delphi yazıyorum sadece merak ediyorum)
        yani demek istediğim fooObject değişkeni bloğun bitiminde yok olmuyor mu ?

        • Merhaba Mehmet,

          fooObject değişkenini local değişken olarak düşünmemiştim. Aslında genel olarak referanssız kalma durumuna değinmiştim. Fakat sorduğun soru için yanlış bilgi vermemek adına hızlıca araştırma yaptım. Aslında JVM çok farklı bir dünya. İçerisinde çok komplike algoritmalar barındırıyor. Bu nedenle bir sonuca varabilmek için nasıl çalıştığını biraz anlamak gerekiyor. Garbage Collector’un nasıl çalıştığını güzel bir şekilde açıklayan aşağıdaki makaleye ulaştım. Çalışma prensibine göz atabilirsin. Kısaca özetlemek gerekirse; Garbage Collector Stack’teki bütün method call’ları tarar. Ardından bu method call’ların Heap’te kullandığı nesnelere “kullanıldığı” için dokunmaz. Fakat method bittiğinde yani senin ifadenle blok bitiminde bu method call Stack’ten düşer. Dolayısıyla Stack’te artık bir bağlantısı bulunmayan başka bir deyişle kullanımda olmayan nesneler de Garbage Collector çalıştığında bellekten kaldırılır. Garbage Collector’un asıl gayesi “kullanılmayan nesne takibi” diyebiliriz. Benim burada verdiğim nokta ise daha çok nesne bazında geçerli.
          Soru için teşekkür ederim.

          https://www.dynatrace.com/resources/ebooks/javabook/how-garbage-collection-works/
          http://programmers.stackexchange.com/questions/113019/why-does-garbage-collection-only-sweep-the-heap

          İyi çalışmalar.

          • Şu sıralar OCA sınavı için Oracle Certified Associate Java 8 Study Guide kitabına çalışıyorum. Local değişken vs Garbage Collector ilişkisi ile ilgili bir bilgiye rastlayınca aklıma burası geldi. Burayı daha temiz bir şekilde açıklamak istedim.

            Sayfa 36, Destroying Objects – Garbage Collection
            An object is no longer reachable when one of two situations occurs:
            ■ The object no longer has any references pointing to it.
            ■ All references to the object have gone out of scope.

            Şimdi burada diyor ki; Bir nesne şu iki durumdan herhangi birinde artık erişilmez olur:
            1. Nesnenin bağlı olduğu herhangi bir referans yoksa (ki benim yazıda ve yorumda belirttiğim gibi)
            2. Nesneye bağlı tüm referanslar scope dışında kalırsa.

            Peki nedir scope dışında kalmak? Kitaptaki örnekle açıklayalım.
            1:public class Scope {
            2: public static void main(String[] args) {
            3: String one, two;
            4: one = new String("a");
            5: two = new String("b");
            6: one = two;
            7: String three = one;
            8: one = null;
            9: }
            10:}

            Şimdi satır satır gidelim.
            3. satırda String tipinden iki adet referans oluşturuluyor.
            4. adımda one isimli referansa bir nesne atanıyor.
            5. adımda two isimli referansa bir başka nesne atanıyor. Şu an iki referans tipimizde birer nesneye sahip.

            6. adımda one isimli referansa two isimli referansın nesnesi atanıyor. Bu şu demek oluyor; hem one hem two isimli referanslar artık aynı nesneye bağlı durumdadır, yani new String(“b”); ifadesi ile oluşturduğumuz nesneye bağlılar. Ancak artık new String(“a”); ifadesi ile oluşturduğumuz nesneye herhangi bir referans değerimiz bağlı değil. Dolayısıyla 6. adımda bu nesne sahipsiz kalıyor, ve Garbage Collector tarafından bellekten kaldırılacak konumuna giriyor.
            7. adımda three isimli yine String tipinde bir referans oluşturuluyor ve buna one isimli referansın nesnesi atanıyor, yani new String(“b”); ifadesi ile oluşturduğumuz nesne. Artık 3 adet referans tipi aynı nesneye bağlı durumda oluyor.

            8. adımda one isimli referansa null değer atanıyor. Böylece o referans değeri artık hiç bir nesneye bağlı değil. Böylece sadece two ve three isimli referans değerleri new String(“b”); ifadesi ile oluşturduğumuz nesneye bağlı.
            9. adımda metodun scope’unun sonuna gelinmiş olunuyor. Şimdi ise ikinci ihtimal olan nesneye bağlı olan referansların scope dışında kalma durumu ortaya çıkıyor. Metod bitiminde yani o scope bittiğinde artık o nesneye bağlı durumda olan two ve three referanslarına ulaşılamayacağı için new String(“b”); ifadesi ile oluşturduğumuz nesnede artık sahipsiz kalıyor, ve Garbage Collector tarafından bellekten kaldırılacak konumuna giriyor.