JVM Anatomisi Quarks
(shipilev.net)- JVM iç yapısına dair bilgileri küçük parçalara bölerek ele alan, her yazının tek bir konuya, teste, benchmark'a veya gözleme odaklandığı devam eden bir mini yazı serisi
- Her yazı 5–10 dakika içinde okunacak uzunlukta olmayı hedefler ve JVM bileşenlerinin birbiriyle etkileştiği varsayımına dayanır
- Dayanaklar ve tartışmalar anekdotsal olabilir; hata, tutarlılık, üslup, dil bilgisi ve tekrar incelemesi yeterince yapılmamış olabilir, bu yüzden olduğu gibi güvenmek konusunda dikkatli olunmalıdır
- Tüm derleme ePUB, MOBI, PDF olarak sunulur; PDF, yüksek kaliteli dönüştürme nedeniyle onlarca MB boyutundadır
- Tekil yazı dizini Compiler, Runtime, GC, Library eksenlerine ayrılır; kilit optimizasyonu, TLAB, GC duraklamaları,
String.intern(), safepoint, sıkıştırılmış referanslar, koşullu taşıma gibi JVM iç konularını ele alır
Seriyi okurken temel varsayımlar
- JVM Anatomy Quarks, JVM'in temel bilgisini kısa yazılar halinde düzenleyen, devam eden bir mini yazı serisidir
- Her yazı tek bir konuya, teste, benchmark'a veya gözleme derinlemesine odaklanır
- Tek bir yazı ayrı ele alındığında bağlam eksik kalabilir ve ele alınan öğelerin çoğu birbiriyle kolayca etkileşime girer
- Yazılardaki dayanaklar ve tartışmalar anekdotsal olabilir; hata, tutarlılık, üslup, dil bilgisi, anlam ve tekrar incelemesi yeterince yapılmamış olabilir
- İçeriği kullanırken veya ona güvenirken risk okuyucuya aittir
Derleme dosyaları ve dizin yapısı
- Tüm seri üç farklı biçimde sunulur
- ePUB en küçüğüdür, 1 MB'tan azdır ve Pandoc HTML-to-ePUB tabanlıdır
- MOBI küçüktür, MB düzeyindedir ve KindleGen ePUB-to-MOBI tabanlıdır
- PDF onlarca MB boyutundadır, oldukça büyüktür ve wkhtmltopdf HTML-to-PDF tabanlı yüksek kaliteli çıktıdır
- Tekil dizinler Compiler, Runtime, GC, Library sınıflandırmalarından oluşur
Konulara göre yazı listesi
-
Compiler odaklı başlıklar
#1: Lock Coarsening and Loops#14: Constant Variables#15: Just-In-Time Constants#16: Megamorphic Virtual Calls#17: Trust Non-Static Final Fields#18: Scalar Replacement#19: Lock Elision#20: FPU Spills#25: Implicit Null Checks#27: Compiler Blackholes#28: Frequency-Based Code Layout#29: Uncommon Traps#30: Conditional Moves
-
Runtime ve GC'nin kesiştiği başlıklar
- JVM çalışırken bellek ve duraklama davranışını ele alan yazılardır
#2: Transparent Huge Pages#4: TLAB Allocation#5: TLABs and Heap Parsability#6: New Object Stages#7: Object Initialization Costs#9: JNI Critical and GC Locker#22: Safepoint Polls
-
GC odaklı başlıklar
- Toplayıcı tasarımı ve heap davranışı merkeze alınır
#3: GC Design and Pauses#11: Moving GC and Locality#13: Intergenerational Barriers#21: Heap Uncommit
-
Runtime odaklı başlıklar
- JVM çalışma ortamı ve nesne gösterimini ele alan yazılardır
#12: Native Memory Tracking#23: Compressed References#24: Object Alignment#26: Identity Hash Code
-
Library veya birleşik sınıflandırma başlıkları
- Library'yi de içeren başlıklardan biri
#10: String.intern()'dir - Compiler ve Runtime birlikte işaretlenen başlıklar
#16,#25,#29,#30'dur
- Library'yi de içeren başlıklardan biri
1 yorum
Hacker News yorumları
https://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-f... gerçekten üzücü bir örnek
Bazı framework'ler JNI ve reflection'ı kötüye kullanarak aslında değişmez olması gereken
finalalanları değiştiregeldiği için, kullanıcı kodu yalnızca sistemin sağladığı sınıflar için mümkün olan önemli optimizasyonları kaçırıyorPlatformlar, özellikle de derleyiciler ve runtime'lar, gelecekteki optimizasyon alanını korumak için anlamsal kısıtları çok sıkı biçimde dayatmalı
Gerçekte
finalı değiştirmesi gereken kod çok fazla değil; bugün bile bu işlem kişinin kendi modülündeki sınıflarla veya açıkçaopenedilmiş sınıflarla sınırlı, dolayısıyla bundan sonra uygulamanınfinalı değiştirmek isteyen modüle yetki vermesi gerekecekYakın zamanda native çağrılar ve güvenli olmayan bellek erişimi için uyguladığımız yönteme benziyor
[1]: https://openjdk.org/jeps/8305968
finalkoyun türünden bir ilk günah yaratmış olabileceğini düşünüyorumBu yüzden artık testlerde
finalsınıfları kolayca mock'layamıyoruz ve mock araçlarıfinalsınıfları mock'lamak için bytecode manipülasyonu bile yapmak zorunda kalıyorÖrneğin Google içinde Effective Java bir gereklilik olduğu için herkese açık GDrive API'sinde bile
finalsınıflar var; oysa dış API tam da mock'lamak isteyeceğiniz şeydirSystem.outörneği Java'nın kendi sorunuhttps://docs.oracle.com/javase/specs/jls/se7/html/jls-17.htm...
Böyle bir emsal varken başkalarının da bunu kabul edilebilir bir yöntem sanması şaşırtıcı değil
Uygun bir baypas prosedüründen geçildiğinde bunların aşılabilmesi doğru olandır
Asıl mesele güvenliktir; çünkü değiştirilemez olanı değiştirip SEGV'ye yol açabilirsiniz ve erişim denetleyicilerinin ele almaya çalıştığı kaygı da tam olarak budur
finalgibi yapan kötü niyetli üç satırlık kodu bizzat yazdığımı kabul ediyorumKeşke engellenmiş olsaydı, ama iş gereksinimi vardı
Biraz farklı bir konu ama Apple yeni Swift Java bridge'ini yayımladı ve oldukça hoş
Hem JNI'ı hem de Panama'yı destekliyor; geçen hafta bunu Android'e port ediyordum
https://github.com/swiftlang/swift-java
Diller arası birlikte çalışabilirlik sayesinde uygun durumlarda tek bir kütüphaneyi birden çok platformda paylaşabiliyorsunuz
Şimdiye kadar bunu yalnızca C++ ile, gerekirse bir C API ekleyerek yapıyorduk; ancak C++'ın kendisine ihtiyaç olmayan durumlarda doğal olarak tercih edilen dil değil
Yine de maliyetten endişeliyim. Mobil uygulamalarda Swift bir Kotlin kütüphanesini kolayca çağırabiliyorsa iOS uygulamasının bir şekilde JVM benzeri bir şeyi yüklemesi gerekmiyor mu diye düşünüyorum; tersine Android uygulaması Swift çağırırsa da Swift runtime'ını yükleyecek gibi görünüyor
Sonuçta bir overhead oluşur
Bir gün geliştiricilerin Swift kütüphanelerine bağımlı olması, o kütüphanenin Kotlin kütüphanelerine bağımlı olup JVM'i ayağa kaldırması ve sonra JNI ile C++ çağırması gibi şeylerin yaygınlaşmasından endişe ediyorum
Bu, modern paket yöneticilerinde doğrudan bağımlılıklarınız birkaç tane olsa da “çok kolay olduğu için umursamamanın” sonucu olarak programın bir anda 100'den fazla geçişli bağımlılığa sahip olmasına benziyor
Bu güzel yazı dizisinin burada paylaşılmasına sevindim. Bu seriden JVM hakkında çok şey öğrendim
Özellikle Java'da sıkça “stack allocation” denilen ifadenin yanlış olduğunu anlatan şu yazıyı seviyorum: https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacemen...
JVM'in gerçekte yaptığı şey escape analysis + scalar replacement
Bu yazıların uzunluğunu seviyorum
Birini birkaç dakika içinde baştan sona okuyabilmek ve isterseniz benchmark'ı yerelde çalıştırabilmek güzel
JVM tabanlı dillerle birkaç yıl çalıştıysanız bu yazı koleksiyonu gerçekten ilginç
Birkaç yıl önce ilk kez okumaya başladığım zamanları hatırlıyorum
Bu serinin adının neden ‘JVM Anatomy Park’tan değiştirildiğini bilen var mı?
Java'yı neredeyse unutmuş durumdayım
Yeni bir projeye Java ile başlamayı hiç düşünmüyorum
Hızlı geliştirme ve esneklik gerekiyorsa Python'ı; çöp toplama olan bir yaklaşımla çok sayıda giriş/çıkış eşzamanlılığını yönetmek istiyorsam Go'yu; derlenen, dengeli ve iyi bir dil gerekiyorsa Swift'i; performans ve güvenlik gereken derlemeli bir dil içinse Rust'ı seçerdim gibi geliyor
Bu yalnızca kişisel tercihim; Kotlin'in Java'yı kullanmayı daha rahat hâle getirdiğini biliyorum ama yine de hissim bu yönde
Java'nın başlıca güçlü yanları; Java deneyimi olan geliştiricilerin neredeyse sınırsız sayıda olması, mevcut kütüphanelerin çok geniş olması ve bunların önemli bir kısmının enterprise odaklı olması, çok sayıda katkıcısı olan çok büyük kod tabanlarını yönetmeyi kolaylaştırması, onlarca yıldır geliştirilen standart VM'inin çok sağlam ve epey hızlı olması ve fiilen her platformda desteklenmesidir
2000'lerin başındaki kadar, hatta enterprise'da bile, ezici bir hâkimiyeti yok ve tipik bir “blub” dili; ancak enterprise ölçeği bekliyorsanız ve saf performanstan ziyade çok sayıda geliştiriciyle ölçeklenmek daha önemliyse gayet makul bir seçim
Rust'ı seviyorum ama geçimimi Java sağlıyor
Modern framework'ler ve yapay zeka destekleri sayesinde birkaç gün içinde düzgün bir backend ayağa kaldırılabiliyor
Tek kişilik teknik kurucu ortak iseniz, MVP'yi hızlıca çıkarmak için Java veya Kotlin ve bir de frontend stack'i bilmeniz yeterli; pratikte kodlama dışındaki işlere çok daha fazla zaman harcayacağınızdan dil özelliklerindeki farklar daha az önemli hâle gelir
Mobilde native'e gidecekseniz Swift ikinci dil olabilir
Ayrıca bir süre boyunca önce ölçeklenebilirliğin sorun olmama ihtimali yüksek. Önce ekip ölçeklenmesi gelir, performans darboğazları ise büyük olasılıkla çok daha sonra görünür olur
Java büyük ekipler için uygundur
İş açısından daha büyük bir yetenek havuzu, hızlı teslim döngüsü ve uzun vadede çekirdek stack olarak kalabilecek bir şey istiyorsanız Java veya Kotlin muhtemelen en iyi seçenek
Belirli bir geliştirici kitlesini çekmek için havalı teknolojileri bir yan hak gibi öne sürüyorsanız ya da nadir bir iş kullanım örneğiniz varsa Go veya Rust'ı seçebilirsiniz
Python akademide ve bootcamp'lerde popüler, ancak genel amaçlı backend'deki iş değerini açıkçası pek göremiyorum
JVM'in tamamını göz ardı etmezdim. JVM bir mühendislik başyapıtı ve günümüzde hızlı evriliyor. Loom, Panama, Leyden gibi projelere bakmak yeterli
Bu yüzden neredeyse her şey için Java oldukça net biçimde iyi bir seçimdir
Java 21+ ile birlikte Kotlin, giriş/çıkış ağırlıklı servisler olsun ya da fiilen herhangi bir servis olsun, benim ilk tercih ettiğim kombinasyon
Kullanması gerçekten rahat; sanal thread'ler sayesinde Go kadar basit ve verimli kod yazmayı mümkün kılarken dünyanın en büyük ve iyi sayılabilecek kütüphane ekosisteminden yararlanabiliyorsunuz
Go'yu ya da Python'ı kötülemek istemiyorum. Tercih ettiğiniz araçlarsa gayet iyiler
Yalnız Java, düşündüğünüz kadar alakasız hâle gelmiş değil