JSE_0006_JIT_Compiler

advertisement
26 Ekim 2016 Çarşamba
Merhaba değerleri Java dostları, bu yazımda adını sıkça duyduğumuz JIT compiler (Just In
Time) hakkında birşeyler yazmak istiyorum. Compiler nedir olaylarına hiç girmek istemiyorum;
çünkü bence bu ayrı bir yazı olabilecek kadar geniş bir konu. Bundan dolayı bu yazımda daha
çok JIT compiler konusuna yoğunluşmak istiyorum.
Malumunuz her yazılım dili bir compiler aracılığı ile makine diline dönüştürülür. Java
gibi WORA – Write Once Run Anywhere – diller ise bu işi ara bir katman ile yapar. Java’ da
yazdığımız kodun çalışma süreci şöyledir.
Kod —> javac —> bytecode —> JVM —> OS
Yazdığımız kod javac derleyici ile bytecode formatına dönüştürülür. Daha sonra bu bytecode
JVM tarafından OS bağlı koda dönüştürülür ve çalıştırılır. İşte bu noktada Java’ nın WORA
olmasını sağlayan bytecode mantığı ve JVM’ dir.
Burada alt bir başlık daha açmam gerekiyor. Compilerlar static ve dynamic olmak üzere
gruplandırılabilir.
Static compiler: Girdi olarak aldığı kod değişmediği müddetçe hep aynı çıktıyı üreten compiler
türüdür. Dolayısıyla daha hızlı çalıştırma ve kod üretme yeteneğine sahiptirler. Yukarıda
verdiğim akışta javac, static bir derleyicidir.
Dynamic compiler: Girdi olarak sadece kod değil aynı zamanda kullanıcı alışkanlığı, kullanım
sıklığı gibi başka parametreleri de alan derleyici tipidir. Static compiler ile karşılaştırınca biraz
daha yavaş kod üretme süreci olabilir; ama runtime anında daha çok verim ve performans
sunarlar. JIT compiler buna örnek verilebilir.
Şimdi biraz daha JIT compiler konusuna şınorkel
ile dalalım. Java JIT compiler çalışma
anında bytecode bloklarını native koda dönüştürür. Yani direkt platform bağımlı bir hale gelir.
Bunu yapmasındaki amaç, çok kullanılan veya çağrılan blokların performansını arttırmaktır.
Peki native kod oluşturma süreci neye belirlenir diye soracak olursanız, cevabı JVM’ de saklı.
JVM çağrılan metot, bloklar vs için bir call count tutar. Bu call count belli bir eşiği yani threshold
aşınca JIT compiler devreye girer kodumuz artık native koda dönüşür ve bytecode ile yer
değiştirir. Ayrıca bu işlemin bir geri dönüşü yoktur. Yani native kod yerine tekrar bytecode
kullanma ihtimali kalmamış oluyor.
Burada eşik değeri parametre aracılığı ile değiştirilebilir. Ayrıca yine belli ayarlarla JIT devre
dışı bırakılabilir. JIT compiler çalışma sırasında her processte olduğu gibi thread yapısına
ihtiyaç duyar. Kullanılacak thread sayısını da belirtebiliriz; ama dikkatli olunması gereken nokta
thread sayısı çok yüksek verilirse bu defa başka processlerin alanı kısıtlanmış olunacaktır.
Şimdi son olarak JIT compiler sürecine bakalım. JIT compiler kodu olduğu gibi native kod
yapısına çevirmemektedir. Belli bir aşamadan ve iyileştirmelerden geçerek nihai native kod
oluşur. Bunlardan bazılarını listelemeye çalıştım.
 Dead Code: Kullanılmayan metotlar değişkenler JIT compiler tarafından elenir. Böylece
boşuna yük alınmamış olunur.
 Inlining: Her ne kadar kodumuz küçük bloklardan oluşsa da native kod çalıştırılırken
bunlar devamlı bir jump anlamına gelir ve maliyetli işlemlerdir. Bundan dolayı JIT compiler
bazı blokları iç içe gömerek bu jump adımlarını minimum sayıya indirmeye çalışır.
 Local Optimization: Blok ve metot içerisindeki küçük parçalarda iyileştirmeler yapılır.
 Control Flow Optimization: Döngü, if, switch gibi akış ve kontrollerde iyileştirmeler yapılır.
 Global Optimization: Metotun tamamı dikkate alınarak iyileştirmeler yapılır.
 Native Code Generation: Son adım olarak native kod oluşur.
Java ve JVM’ nin temel ve önemli konularından birisi olduğunu düşündüğüm JIT compiler
konusuna değinmeye çalıştım. Umarım faydalı olmuştur.
Bol Java’ lı günler dileğiyle…
https://twitter.com/farukbozan

http://www.farukbozan.com/anajavatica/
Download