1 puan yazan GN⁺ 2024-11-12 | 1 yorum | WhatsApp'ta paylaş
  • 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

1 yorum

 
GN⁺ 2024-11-12
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 final alanları 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ıyor
    Platformlar, özellikle de derleyiciler ve runtime'lar, gelecekteki optimizasyon alanını korumak için anlamsal kısıtları çok sıkı biçimde dayatmalı

    • integrity by default stratejimizin [1] bir parçası olarak bunu değiştiriyoruz ve yakında ilgili bir JEP gelecek
      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ça open edilmiş sınıflarla sınırlı, dolayısıyla bundan sonra uygulamanın finalı değiştirmek isteyen modüle yetki vermesi gerekecek
      Yakı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
    • Bazılarının Effective Java'yı körü körüne izleyip her şeye final koyun türünden bir ilk günah yaratmış olabileceğini düşünüyorum
      Bu yüzden artık testlerde final sınıfları kolayca mock'layamıyoruz ve mock araçları final sı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 final sınıflar var; oysa dış API tam da mock'lamak isteyeceğiniz şeydir
    • System.out örneği Java'nın kendi sorunu
      https://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
    • Alan niteleyicileri güvenlik kısıtı değil, anlamsal kısıttır
      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
    • Uzun zaman önce ortadan kalkmış bir iç kütüphanede sıkıntılı bir refactoring'den kaçınmak için bir üyeyi “un-final” yapan, değiştiren ve sonra yeniden final gibi yapan kötü niyetli üç satırlık kodu bizzat yazdığımı kabul ediyorum
      Keş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

    • “Modern” denebilirse, günümüzdeki cross-platform yaklaşım ilginç
      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ı?

    • Justin Rolland'ın çevrimiçi davranışlarıyla ilgili şeyler ilk ortaya çıkmaya başladığında adını değiştirdiklerini düşünüyorum
  • 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

    • Sadece ben böyle düşünmüyorumdur, ama muhtemelen Java'ya ihtiyaç duymadığım durumlardayım
      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
    • Diğer yanıtlara ek olarak, Java startup'ların ihtiyaç duyduğu özelliklere de yeterince sahip olduğu için yeni projelerde kullanmak mantıklı
      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 üzerinde Clojure gibi kullanımı çok rahat pek çok dil var
      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
    • Alevlenmeye müsait bir yoruma alevlenmeye müsait bir yanıt verecek olursam, Java her açıdan Go'dan daha iyidir ve verdiğiniz neredeyse tüm örneklerin %90'ı Java ile halledilebilir
      Bu yüzden neredeyse her şey için Java oldukça net biçimde iyi bir seçimdir
    • Sadece siz böyle değilsiniz, ama herkes de böyle değil
      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