- JVM belleği neye bölünür?
- Çöp toplama nasıl çalışır? Hangi toplayıcıyı seçmeli?
- Adım adım ayar: önce hedefi, sonra ölçümü yazın
- Heap boyutlandırma: -Xms, -Xmx ve konteynerlerde yüzde ayarı
- Belirtiden nedene: GC problemi nasıl teşhis edilir?
- Sık yapılan hatalar
- Bu beceriyi Mindset programlarında nerede çalışırsınız?
- Sık sorulan sorular
JVM bellek yönetimi ve çöp toplama ayarı: ölçerek adım adım
JVM bellek bölgeleri, çöp toplayıcı seçimi, heap boyutlandırma, GC günlüğü ve heap dökümüyle teşhis: ölçüme dayalı ayar rehberi.
JVM belleği neye bölünür?
JVM ayarına geçmeden önce belleğin nerede kullanıldığını bilmek gerekir. Bir Java süreci tek parça bellek tüketmez; farklı bölgelerin toplamıdır.
- Heap: Nesnelerin yaşadığı bölge. Çoğu çöp toplayıcı heap'i genç nesneler ve yaşlı nesneler olarak ayırır; yeni oluşan nesneler genç bölgeye düşer, uzun yaşayanlar yaşlı bölgeye taşınır
- Metaspace: Sınıf meta verisinin tutulduğu, yerel bellekte yer alan bölge. Sınıf yükleyicisi sızıntıları burada belirtisini verir
- Thread yığınları: Her iş parçacığının kendi yığını vardır; çok sayıda iş parçacığı bellek tüketir
- Doğrudan (direct) ve yerel bellek: NIO tamponları, JIT derlenmiş kod, kütüphanelerin yerel ayırmaları. Heap ayarı bu kısmı kapsamaz
Bunun pratik sonucu şudur: heap'e verdiğiniz üst sınır, sürecin toplam bellek tüketimi değildir. Konteyner içinde çalışan bir uygulamada heap, metaspace, yığınlar ve yerel bellek birlikte konteyner limitinin altında kalmalıdır; yoksa uygulama Java hatası vermeden işletim sistemi tarafından sonlandırılabilir.
Çöp toplama nasıl çalışır? Hangi toplayıcıyı seçmeli?
Çöp toplayıcının işi birkaç parçalıdır: uygulamaya bellek ayırmak, hâlâ kullanılan nesneleri belirlemek ve gerisini geri kazanmak. Resmî ayar kılavuzu, küçük uygulamalarda çöp toplama yükünün çoğu zaman önemsiz olduğunu, ancak büyük ve çok iş parçacıklı uygulamalarda ciddi bir darboğaza dönüşebileceğini vurgular. Toplayıcı seçimi bu yüzden önemlidir.
Başlıca seçenekler: • G1: Sunucu sınıfı makinelerde varsayılandır. Büyük heap'lerde duraklama süresi hedefini yüksek olasılıkla tutarken iyi bir verim sağlamayı amaçlar • ZGC: Duraklamaları çok kısa tutmayı hedefleyen düşük gecikmeli toplayıcıdır; karşılığında bir miktar verim kaybı olabilir. Duraklama süreleri heap boyutundan bağımsızdır • Parallel: Verim toplayıcısı olarak da bilinir; çok işlemcili makinelerden yararlanarak toplam çalışma hızını artırmayı hedefler • Serial: Küçük ve basit uygulamalar için genellikle yeterli seçimdir
Toplayıcı bayrakları şunlardır: -XX:+UseG1GC, -XX:+UseZGC, -XX:+UseParallelGC, -XX:+UseSerialGC. Varsayılanla başlamak çoğu zaman en doğrusudur; değiştirmek için ölçülmüş bir nedeniniz olsun. Örneğin hizmet seviyesi sözleşmenizde gecikme kritikse ZGC'yi, toplu iş (batch) gibi toplam çalışma süresi önemliyse Parallel'i değerlendirirsiniz.
Adım adım ayar: önce hedefi, sonra ölçümü yazın
GC ayarı sezgiyle değil, ölçümle yapılır. Sıra şöyledir:
Hedefi belirleyin. Hangisi sizin için öncelikli: toplam verim, istek gecikmesi (duraklama süresi) ya da bellek ayak izi? Hepsini aynı anda optimize edemezsiniz; hedef toplayıcı ve ayar tercihini belirler.
GC günlüğünü açın. Birleşik günlükleme kullanarak: -Xlog:gc*:file=gc.log. Günlük; duraklama sürelerini, toplama sıklığını ve toplamadan sonra heap'te kalan miktarı gösterir. Üretimde düşük maliyetle açık bırakılabilir.
Yük altında ölçün. Gerçekçi bir yük altında günlüğü toplayın. Toplamadan sonra kalan heap miktarı yükseldikçe yükseliyorsa sorun ayar değil, bellek sızıntısıdır.
Tek bir ayarı değiştirin. Örneğin heap boyutunu büyütün ya da duraklama hedefi koyun: -XX:MaxGCPauseMillis=<ms>. Resmî belgeye göre bu esnek bir hedeftir; JVM elinden geleni yapar ama sonucu önceden taahhüt etmez. G1 için varsayılan bir hedef zaten vardır.
Sonucu karşılaştırın ve kaydedin. Duraklama dağılımı iyileştiyse ama verim düştüyse bu bir değiş tokuştur; hedefinize göre kabul edilebilir mi karar verin.
Heap boyutlandırma: -Xms, -Xmx ve konteynerlerde yüzde ayarı
Heap'in başlangıç boyutunu -Xms, azami boyutunu -Xmx belirler:
java -Xms<boyut> -Xmx<boyut> -jar uygulama.jar
Resmî belgeye göre sunucu dağıtımlarında -Xms ve -Xmx çoğunlukla aynı değere ayarlanır; böylece JVM çalışırken heap'i büyütüp küçültme maliyeti ortadan kalkar. Boyut son ek olarak k, m ya da g alır.
Konteynerlerde sabit boyut yazmak yerine -XX:MaxRAMPercentage=<yüzde> ile heap'i kullanılabilir belleğe oranlayabilirsiniz; konteyner limiti değiştiğinde ayar kendini uyarlar. Varsayılan oran düşüktür, bu yüzden büyük limitli konteynerlerde belleğin büyük bölümü kullanılmadan kalabilir; ancak heap dışı alanlara da yer bıraktığınızdan emin olun.
Thread yığını için -Xss, metaspace üst sınırı için -XX:MaxMetaspaceSize kullanılır; metaspace sınırı varsayılan olarak koyulmamıştır. Sınır koymak sınıf yükleyicisi sızıntısını erken ve belirgin bir hatayla yakalamanıza yardım eder.
Son olarak, bellek tükendiğinde teşhis için bir iz bırakın: -XX:+HeapDumpOnOutOfMemoryError. Etkinleştirildiğinde OutOfMemoryError anında heap dökümü dosyaya yazılır; varsayılan olarak kapalıdır. Dosya yolunu -XX:HeapDumpPath ile verebilirsiniz. Döküm büyük olacağından yeterli disk alanını önceden planlayın.
Belirtiden nedene: GC problemi nasıl teşhis edilir?
Belirtilere göre ilk bakılacak yer değişir: • Zaman zaman uzun duraklamalar: GC günlüğünde uzun duraklamaların hangi toplama türünde olduğuna bakın; heap çok küçükse toplamalar sıklaşır, çok büyükse bazı toplayıcılarda tek duraklama uzar • Heap dolu kalıyor, sürekli büyüyor: Büyük olasılıkla sızıntı. Çalışan sürecin heap dökümünü jcmd <pid> GC.heap_dump <dosya> ile alın ve analiz aracıyla en çok yer tutan nesne zincirlerine bakın • OutOfMemoryError: Java heap space: Heap yetersiz ya da sızıntı var. Metaspace hatası ise sınıf yükleme sorununa işaret eder • Konteyner sonlandırılıyor ama Java hatası yok: Heap dışı bellek (yığınlar, direct bellek, metaspace) limiti aşıyor olabilir; heap'i konteyner limitine çok yakın tutmayın • Yüksek işlemci kullanımı, düşük verim: Toplama sıklığına ve ayırma hızına bakın. Gereksiz nesne üretimi (döngülerde sürekli yeni nesne, gereksiz kutulama) toplayıcıyı yorar; çoğu zaman ayardan çok kod düzeltmesi çözer
Anlık durum için jcmd <pid> GC.heap_info heap kullanımını, jstat -gcutil <pid> ise toplama istatistiklerini gösterir. Bunları günlükle birlikte okuyun.
Sık yapılan hatalar
- Tüm bayrakları internetten kopyalayıp bir arada denemek; hangisinin işe yaradığı anlaşılmaz
- Varsayılan toplayıcıyı gerekçesiz değiştirmek
- Heap'i artırarak sızıntıyı çözmeye çalışmak; sızıntı sadece daha geç patlar
- Konteyner limitini heap ayarıyla birleştirmemek
- Geliştirme laptop'unda yaptığı ayarı üretim yüküne uyarlamadan taşımak
- Günlüğü kapalı tutup sorun anında geriye dönük veri bulamamak
- Ayar değişikliğini sürüm kontrolünde ve yayın notunda belgelememek
Ayar, kodun yerini tutmaz: aşırı nesne üretimi, kontrolsüz önbellekler ve kapatılmayan kaynaklar önce kodda düzeltilmelidir.
Bu beceriyi Mindset programlarında nerede çalışırsınız?
JVM bellek ve çöp toplama bilgisi; Java ile yüksek trafikli servis geliştiren backend mühendisleri, performans mühendisleri ve konteyner ortamında Java işleten platform ekipleri için kritik bir ayrıntıdır. Çözülen sorun, tahmine dayalı ayarlar yerine ölçüme dayalı bellek yönetimidir.
Java İleri Seviye: JVM Performans ve Bellek Yönetimi eğitiminde JVM mimarisi ve bellek bölgeleri, çöp toplama algoritmaları ve ayar, konteyner ve kapasite planlaması ayrı modüllerdir. Ekipler kendi servislerinin GC günlüğünü bu eğitimin akışıyla birlikte okuyarak somut bir çalışma yapabilir.
İlgili Mindset programı
Java İleri Seviye: JVM Performans ve Bellek Yönetimi
Sık sorulan sorular
Hangi çöp toplayıcıyı seçmeliyim?
Ölçüm yapmadan varsayılanı değiştirmeyin. Sunucu sınıfı makinelerde G1 varsayılandır ve çoğu iş yükü için dengeli bir başlangıçtır. Gecikme çok kritikse ZGC, toplam verim önemliyse Parallel, küçük ve basit uygulamalarda Serial düşünülür. Karar vermeden önce kendi iş yükünüzü gerçekçi yük altında deneyin.
-Xms ve -Xmx neden aynı yapılır?
Resmî belge sunucu dağıtımlarında bu bayrakların çoğunlukla aynı değere ayarlandığını belirtir. Böylece heap, çalışma sırasında büyüyüp küçülmez; bu yeniden boyutlandırma maliyetini ve öngörülemeyen davranışı önler. Konteynerde sabit boyut yerine yüzdeyle ayarlama da bir seçenektir.
Bellek sızıntısını nasıl anlarım?
Toplamadan sonra heap'te kalan miktar zaman içinde sürekli artıyorsa sızıntıdan şüphelenilir. GC günlüğünde bu eğilimi izleyin, sonra heap dökümü alıp hangi nesne türlerinin ve referans zincirlerinin yer tuttuğunu analiz edin. Uygulama davranışı ile birlikte okumak şarttır.
OutOfMemoryError aldığımda hemen heap'i büyütmeli miyim?
Hayır. Önce nedenini anlayın: gerçek yük artışı mı, sızıntı mı, yoksa tek bir istekte yüksek tüketim mi? Heap dökümü bu soruyu yanıtlar. Büyütmek sızıntı varsa sorunu yalnızca erteler. Dökümü kaydedebilmek için bellek tükendiğinde dökümü yazan bayrağı önceden açık bırakın.
İlgili rehberler
Kategori: Yazılım Geliştirme