Java İle Java Flight Recorder Kullanarak Bellek Sızıntısı Analizi Nasıl Yapılır?

Java İle Java Flight Recorder Kullanarak Bellek Sızıntısı Analizi Nasıl Yapılır?
Java İle Java Flight Recorder Kullanarak Bellek Sızıntısı Analizi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Java Flight Recorder kullanabilmek için modern bir Java sürümüne ihtiyacınız vardır. Java 11 ve sonraki sürümlerde JFR, JVM içerisine gömülü olarak gelir ve ek bir lisans gerektirmez. Çalışma ortamınızın hazır olduğundan emin olmak için aşağıdaki adımları kontrol edin.

  • Java 17 veya 21 (LTS sürümlerinin kullanılması önerilir).
  • JDK (Java Development Kit) kurulu olmalıdır (JRE sadece çalıştırmak içindir, analiz için JDK gerekir).
  • Uygulamanızın çalıştığı sunucuda komut satırı erişimi.
  • JDK ile birlikte gelen jcmd ve jmc (Java Mission Control) araçları.

Adım 1: Uygulamayı JFR ile İzleme Modunda Başlatma

Bellek sızıntısı analizi yapabilmek için uygulamanın çalışma süresi boyunca veri toplaması gerekir. Uygulamanızı başlatırken JFR'ı aktif hale getirmek için JVM parametrelerini kullanmalısınız. Bu parametreler, uygulamanın bellek kullanımını sürekli izleyerek bir kayıt dosyası oluşturmasını sağlar.

java -XX:StartFlightRecording=filename=bellek_analizi.jfr,duration=60s,settings=profile -jar uygulama.jar

Yukarıdaki komut, 60 saniyelik bir kayıt başlatır ve verileri bellek_analizi.jfr dosyasına yazar. settings=profile parametresi, bellek tahsisleri hakkında detaylı bilgi toplamak için kritik öneme sahiptir.

Adım 2: Çalışan Bir Uygulamada JFR Kaydını Tetikleme

Eğer uygulamanız zaten çalışıyorsa ve bir bellek sızıntısı olduğundan şüpheleniyorsanız, uygulamayı yeniden başlatmadan da JFR kaydını başlatabilirsiniz. Bunun için jcmd aracını kullanırız. Bu araç, çalışan JVM süreçlerine komut göndermemizi sağlar.

# Çalışan Java süreçlerini listele
jcmd

# Belirli bir PID (süreç kimliği) için kayıt başlat
jcmd  JFR.start duration=120s filename=canli_analiz.jfr settings=profile

Bu yöntem, üretim ortamındaki (production) anlık bellek artışlarını yakalamak için en güvenli yoldur. Kayıt süresini ihtiyaca göre (örneğin 300s) uzatabilirsiniz.

Adım 3: Bellek Sızıntısı İçeren Kod Yapısı

Bellek sızıntısı genellikle statik listeler veya kapatılmayan kaynaklar nedeniyle oluşur. Aşağıdaki örnek, bir bellek sızıntısının nasıl oluştuğunu göstermektedir. Bu kod, her istekte bir nesneyi static bir listeye ekler ve hiçbir zaman temizlemez.

import java.util.ArrayList;
import java.util.List;

public class SızıntıYapanServis {
    // Statik liste bellek sızıntısının ana kaynağıdır
    private static final List sızıntıListesi = new ArrayList();

    public void veriEkle(Object veri) {
        sızıntıListesi.add(veri);
    }
}

Bu kodda sızıntıListesi nesnesi uygulama yaşadığı sürece bellekte kalır. JFR analizinde bu nesnenin sürekli büyüdüğünü ve Garbage Collector tarafından temizlenemediğini göreceğiz.

Adım 4: JFR Dosyasını Java Mission Control (JMC) ile Analiz Etme

Veri toplandıktan sonra, bu dosyayı görselleştirmek için Java Mission Control (JMC) aracını kullanmalıyız. JMC, JFR dosyalarını açarak bellek kullanımındaki "Memory Leak" şüpheli alanları grafiklerle gösterir.

  1. JMC uygulamasını açın.
  2. File -> Open File yolunu izleyerek bellek_analizi.jfr dosyasını seçin.
  3. "Memory" sekmesine gidin.
  4. "Allocation in New TLABs" veya "Old Object Sample" kısımlarına bakın.

Bu bölümde, en çok bellek tüketen nesneleri ve bu nesneleri tutan referans zincirini (GC Root) görebilirsiniz. Sızıntı yapan nesneler genellikle "Old Object" (Eski Nesne) olarak işaretlenir.

Adım 5: Bellek Analizi Yöntemleri Karşılaştırması

Bellek sızıntılarını analiz etmek için farklı araçlar mevcuttur. Aşağıdaki tablo, JFR'ın diğer yöntemlere göre avantajlarını özetlemektedir.

Yöntem Avantaj Dezavantaj
JFR (Flight Recorder) Çok düşük performans kaybı, üretim ortamına uygun. Zaman damgalı analiz gerektirir.
Heap Dump (jmap) Anlık bellek görüntüsü, çok detaylı. Uygulamayı dondurur, büyük dosya boyutu.
VisualVM Görsel ve kolay arayüz. Üretim ortamı için uygun değildir.

Adım 6: Yaygın Hatalar ve Debug İpuçları

Bellek sızıntısı analizinde yapılan en büyük hata, sadece "Heap" boyutuna bakmaktır. Oysa önemli olan, nesnelerin neden silinmediğidir. Aşağıdaki ipuçları analizinizi hızlandıracaktır.

  • Statik Koleksiyonlar: Global değişken olarak tanımlanan listeler veya map'ler sızıntıların bir numaralı sebebidir.
  • ThreadLocal Kullanımı: İş parçacığı bazlı değişkenler, thread havuzları ile kullanıldığında temizlenmeyebilir.
  • Kapatılmayan Kaynaklar: Veritabanı bağlantıları veya dosya akışları (Stream) mutlaka try-with-resources bloğu ile kapatılmalıdır.
// Doğru kullanım: try-with-resources
try (BufferedReader br = new BufferedReader(new FileReader("dosya.txt"))) {
    return br.readLine();
} catch (IOException e) {
    // Hata yönetimi
}

Güvenlik Uyarısı: Üretim ortamında JFR kayıtları alırken dosya boyutunu sınırlayın. Çok uzun süreli kayıtlar disk alanını doldurabilir. Ayrıca, JFR dosyaları uygulamanızdaki hassas verileri (bellekteki nesnelerin içeriğini) içerebileceğinden, bu dosyaları güvenli bir şekilde saklayın ve analiz sonrası silin.

Sıkça Sorulan Sorular

JFR üretim ortamında uygulamayı yavaşlatır mı?

Hayır, JFR çok düşük bir overhead (ek yük) ile çalışacak şekilde tasarlanmıştır. Genellikle uygulamanın performansını %1'den daha az etkiler.

Bellek sızıntısı olduğunu nasıl kesin anlarım?

Eğer uygulamanızın Heap kullanımı (GC sonrası) her döngüde artıyorsa ve asla başlangıç seviyesine düşmüyorsa, bu kesin bir bellek sızıntısı işaretidir.

JMC aracı ücretsiz mi?

Evet, Java Mission Control açık kaynaklı bir projedir ve Oracle tarafından desteklenmektedir.

JFR kayıt dosyasını başka bir bilgisayarda analiz edebilir miyim?

Evet, JFR dosyaları taşınabilirdir. Üretim sunucusundan aldığınız dosyayı kendi yerel makinenizdeki JMC ile analiz edebilirsiniz.

Hangi JVM parametreleri sızıntı takibi için en iyisidir?

-XX:+HeapDumpOnOutOfMemoryError parametresini JFR ile birlikte kullanmak, sızıntı kritik seviyeye ulaştığında otomatik dump alarak analiz şansınızı artırır.

Sorumluluk Reddi: Bu makaledeki kod örnekleri ve analiz yöntemleri eğitim amaçlıdır. Yazılımınızdaki bellek sızıntılarını gidermeden önce mutlaka test ortamında doğrulama yapın. Yanlış analizler veya hatalı kod düzeltmeleri uygulamanızın kararlılığını bozabilir.

JFR ile Otomatikleştirilmiş İzleme ve CI/CD Entegrasyonu

Bellek sızıntılarını manuel olarak takip etmek zaman alıcıdır. Profesyonel projelerde, JFR kayıtlarını belirli aralıklarla veya uygulama kritik bir eşiğe ulaştığında otomatik olarak tetiklemek, "post-mortem" (olay sonrası) analiz için hayati önem taşır. Özellikle Kubernetes veya Docker ortamlarında, pod yeniden başlatılmadan önce JFR verilerini dış bir depolama alanına aktarmak için jcmd komutunu bir yan süreç (sidecar) olarak kullanabilirsiniz.

Aşağıdaki örnek, uygulamanızın bellek kullanımı %80'i aştığında otomatik olarak JFR kaydı başlatan basit bir Java izleme mantığını göstermektedir:

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;

public class MemoryMonitor {
    public static void checkMemoryAndTriggerJFR() {
        MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        double usage = (double) memoryBean.getHeapMemoryUsage().getUsed() / 
                       memoryBean.getHeapMemoryUsage().getMax();

        if (usage > 0.8) {
            System.out.println("Bellek kullanımı %80 üzerinde! JFR kaydı başlatılıyor...");
            try {
                // JFR kaydını programatik olarak tetikleme komutu
                ProcessBuilder pb = new ProcessBuilder("jcmd", 
                    String.valueOf(ProcessHandle.current().pid()), 
                    "JFR.start", "duration=60s", "filename=leak_dump.jfr");
                pb.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

JFR Verilerini Komut Satırı ile Sorgulama (jfr tool)

Grafiksel arayüz (JMC) her zaman erişilebilir olmayabilir. Özellikle uzak sunucularda veya kısıtlı ağ ortamlarında, jfr komut satırı aracı ile ham veriyi analiz edebilirsiniz. Bu araç, büyük kayıt dosyalarını hızlıca filtrelemek ve belirli olayları (event) ayıklamak için mükemmeldir.

Örneğin, bellek sızıntısına neden olan en çok nesne tahsisini (allocation) görmek için şu komutu kullanabilirsiniz:

# Kayıt dosyasındaki tüm nesne tahsis olaylarını listeler
jfr summary leak_dump.jfr

# Sadece belirli bir zaman aralığındaki bellek olaylarını filtreler
jfr print --events jdk.ObjectAllocationInNewTLAB leak_dump.jfr > allocation_report.txt

Bu yöntem, özellikle CI/CD süreçlerinde otomatik testler sonucunda oluşan JFR dosyalarını analiz ederek, "bellek tüketimi artışı" (memory regression) durumunda build işlemini başarısız saymanıza olanak tanır. Aşağıdaki tablo, JFR ile analiz yaparken dikkat etmeniz gereken kritik olay türlerini özetlemektedir:

Olay Türü Analiz Amacı
jdk.ObjectAllocationInNewTLAB Hangi sınıfların en çok bellek tükettiğini belirlemek.
jdk.GCPhasePause GC duraklamalarının bellek doluluğu ile ilişkisini görmek.
jdk.HeapSummary Uygulama yaşam döngüsü boyunca heap boyutunun değişimini izlemek.

Bu verileri düzenli olarak toplamak, uygulamanızın "bellek profili"ni çıkarmanızı sağlar. Bellek profili, uygulamanızın normal çalışma koşullarında ne kadar heap tükettiğini gösteren bir referans noktasıdır. Bu referans noktasından sapmalar, sızıntının ilk belirtisi olarak kabul edilmelidir.

Sonuç

Java Flight Recorder, bellek sızıntılarını tespit etmek için modern Java geliştiricilerinin elindeki en güçlü araçtır. Bu rehberde öğrendiğiniz yöntemlerle, uygulamanızın bellek tüketimini izleyebilir, sızıntı yapan nesneleri tanımlayabilir ve daha kararlı Java uygulamaları geliştirebilirsiniz. Bir sonraki adım olarak, uygulamanızdaki "Garbage Collection" duraklamalarını (GC Pauses) analiz etmeyi ve JFR ile uygulama yanıt sürelerini optimize etmeyi öğrenebilirsiniz.

Bu yazıya tepkinizi paylaşın:
Burak Yılmaz

Mutfak teknikleri ve pratik gastronomi ipuçları üzerine beş yıllık deneyime sahibim. Okuyucuların mutfak süreçlerini hızlandıracak ve kolaylaştıracak rehberler hazırlıyorum.

Yorumlar (0)

Yorum Yaz