Sınıf Yükleme ve JIT — Uygulama Neden Isınır?
Önce şunu oku: Polimorfizm ve Dinamik Bağlama — Kararı Kim Veriyor?
30 saniyede özet
JVM kodu önce satır satır okur, sık çalışanı zamanla hızlı makine koduna çevirir; tahmini yanlış çıkarsa geri döner. Yeni sürüm yayına alınınca ilk dakikalardaki yavaşlığın sebebi bu ısınmadır.
Her yeni sürümü yayına aldıktan sonra site ilk birkaç dakika ağırlaşıyor ve alarm çalıyor. Sonra kendiliğinden düzeliyor. Kodda değişen bir şey yok.
-
Bayt: Her yeni sürümden sonra site ilk dakikalarda ağırlaşıyor, alarm çalıyor!
-
Sen: Sonra ne oluyor?
-
Bayt: Sonra kendiliğinden düzeliyor. Kodda da değişen bir şey yok!
-
Bayt: JVM de yeni işe başlayan biri gibi: önce el kitabından okur, sonra hızlanır.
Sınıf ilk kullanımda yüklenir
JVM, uygulamadaki her sınıfı başlangıçta yüklemez. Bir sınıfı ilk kez gerçekten kullandığında bir class loaderBir sınıfın bytecode'unu bulup JVM'e yükleyen nesne. Sınıflar başlangıçta değil, ilk gerçek kullanımda yüklenir ve static başlatıcıları bir kez çalışır.Sözlükte gör → onu bulur, doğrular ve static başlatıcılarını çalıştırır.
Bu bir kez ve thread-safe olur. Ama static init bir exception fırlatırsa sınıf o JVM’de bozuk kalır: ilk denemede ExceptionInInitializerError, sonrakilerde NoClassDefFoundError.
Kafam karıştı, daha basit anlat
JVM bir sınıfı ancak ilk kez gerçekten ihtiyaç duyduğunda raftan indirir. İndirirken bir şey ters giderse, o sınıf program kapanana kadar bozuk kalır.
Bir sınıfın static başlatıcısı ne zaman çalışır?
Yavaş başla, hızlan
Kod önce yorumlanır. Sık çağrılan metodu JIT derleyiciÇalışma sırasında sık çağrılan bytecode'u makine koduna çeviren derleyici. HotSpot'ta C1 hızlı derleyip profil toplar, C2 bu profile göre optimize eder.Sözlükte gör → derler: önce C1 hızlıca derler ve hangi tiplerin, hangi dalların geldiğini sayar. Profil yeterince dolunca C2, bu profile güvenerek agresif optimize eder.
C2, total() içindeki item.price() çağrısını hep Book gördüğü için Book.price() olarak inline etti. Sonra ilk kez bir Gift geliyor. Ne olur? Cevabı göster
Kod geçersiz sayılır. C2 bir tip kontrolü bırakmıştı; kontrol tutmayınca metot yorumlayıcıya döner, yeniden profil toplanır ve yeniden derlenir.
Adım adım oku
- Uygulama açılınca kod yorumlayıcıyla, yani el kitabından okunarak çalışır ve yavaştır.
- Sık çalışan metotlar önce C1 ile hızlıca, sonra toplanan profille C2 ile iyice derlenir.
- C2'nin varsaydığı tip dışında bir nesne, örneğin ilk Gift gelince derlenmiş kod bırakılır: deopt.
- JVM yeni bilgiyle kodu yeniden derler ve yanıt süresi tekrar düşer.
Buna deoptimizationJIT'in bir varsayıma (ör. 'buraya hep Book gelir') dayanarak ürettiği kodun, varsayım bozulunca geçersiz sayılıp yorumlayıcıya dönülmesi.Sözlükte gör → denir. Hata değildir; JIT’in spekülasyonunun bedelidir. Ama sık oluyorsa, ısınma boşa gidiyordur.
Kafam karıştı, daha basit anlat
JIT, “Just-In-Time”, yani tam zamanında derleme demek. JVM önce kodu yavaşça okur, sık kullanılan yerleri fark edince onları hızlı makine koduna çevirir.
JIT bağlamında deoptimization ne zaman olur?
Kendin gör
Deploy sonrası ilk dakikalar — JIT ne yapıyor?
Tohum 962484- yorumlayıcı
- C1
- C2
- deoptimization
Oynat ya da adımla.
Şu an ne oldu?
Yeni sürüm deploy edildi; total() her istekte çağrılıyor
JVM kodu önce yorumlar, sonra sık çağrılanı derler. Kullanıcılar bu sürecin hangi kısmını yaşıyor?
Görevler0/3
Gerçek kullanıcılar yorumlayıcıda çalışan kodla karşılansınaçık
İpucu
Isınma olmadan trafiğe açıl.
Isındığı hâlde canlı trafikte deoptimization yaşaaçık
İpucu
Isınma, gerçek trafiğin bir kısmını hiç görmesin.
Yeni tip gelse de canlı trafiğin tamamı C2 ile karşılansınaçık
İpucu
Isınma gerçek trafiğe benzesin.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Isınma yok: ilk canlı batch yorumlayıcıda, sınıf yükleme de kullanıcının üstünde.
- Isınmayı “sentetik” yap. Canlı trafik C2 ile başlıyor, ama Gift gelince deoptimization.
- Isınmayı “temsili” yap. Canlı trafiğin tamamı C2.
- Trafiği “yalnızca Book” yap. Sentetik ısınma artık yetiyor; çünkü trafik ona benziyor.
Simülatörde sentetik (yalnızca Book) ısınmadan sonra canlı trafik C2 ile başladı, ama Gift gelince deoptimization oldu. Buradan çıkan ders ne?
Trafikten önce ısın
Deploy sonrası yavaşlığın kaynakları birden fazladır: sınıf yükleme, yorumlayıcı, boş bağlantı havuzu, soğuk cache. JVM tarafını azaltmanın yolları:
- Temsili ısınma: gerçek trafiğe benzeyen istekler, readiness probe’u açılmadan önce.
- Kademeli trafik: yeni instance’a yükü yavaş yavaş vermek.
- Başlangıç arşivleri: CDS ve JDK 24 ile gelen Project Leyden AOT cache’i, sınıf yükleme işinin bir kısmını önceki çalıştırmadan getirir.
Kafam karıştı, daha basit anlat
Yeni açılan uygulama soğuk bir motor gibidir. Gerçek trafik gelmeden önce benzer isteklerle ısıtırsan, ilk kullanıcılar yavaşlığı hissetmez.
Kubernetes'te yeni pod'lar trafiğe girer girmez birkaç dakika yüksek gecikme gösteriyor. Hangisi JVM ısınmasını kullanıcıdan uzak tutmanın en doğrudan yolu?
Tuzaklar
Elle yazılmış benchmark. Isınmayan, sonucu kullanılmayan bir System.nanoTime() döngüsü ya yorumlayıcıyı ölçer ya da JIT’in sildiği boş bir döngüyü. JMH kullan.
Static init’te I/O. Dosya ya da ağ hatası sınıfı kalıcı olarak bozar. Pahalı ve hata verebilen işi açık bir başlatma metoduna taşı.
Tek tipe göre ısınma. Sentetik ısınma yalnızca mutlu yolu çağırıyorsa, gerçek trafikteki ilk farklı istek deoptimization getirir.
Log'da önce bir `ExceptionInInitializerError`, sonraki her istekte `NoClassDefFoundError: Could not initialize class TaxRules` görüyorsun. Sınıf dosyası jar'da duruyor. Ne oldu?
Bu 'benchmark', iki uygulamayı karşılaştırmak için kullanılıyor. En ciddi sorunun olduğu satır hangisi?
Aşağıdaki örnek bir bankanın hesap ekstresi servisinden: class loading bir format eklenti sistemiyle, JIT de doğru ölçüm düzeneğiyle gösteriliyor. ServiceLoader ile keşfedilen formatlar, tembel statik başlatma ve ısınmayı hesaba katan bir JMH benchmark’ı.
Derinleş · Hesap ekstresi formatları: class loading ve JIT 6 dosya · ~90 satır · ilk okumada atlayabilirsin
Kendini sına
JVM bütün sınıfları uygulama açılırken bir kerede yükler.
Program ne yazdırır?
Aklında kalacak üç şey
- 1 Sınıf program başlarken değil, ilk kullanıldığında yüklenir ve static kısmı bir kez çalışır. Bu adım hata verirse sınıf o JVM'de bir daha kullanılamaz.
- 2 JIT, o ana kadar gördüğüne güvenerek optimize eder. Beklenmedik bir tip ya da yol gelince optimizasyon geri alınır ve metot yeniden ısınır.
- 3 Isınma gerçek trafiğe benzemeli ve uygulama trafiğe açılmadan bitmeli. Hız iddiası JMH ya da gerçek yük testiyle ölçülür.
4 kart sonraki derste seni bekliyor