1 Punkte von GN⁺ 2024-11-12 | 1 Kommentare | Auf WhatsApp teilen
  • Eine fortlaufende Mini-Post-Serie, die internes JVM-Wissen in kleine Einheiten zerlegt; jeder Beitrag konzentriert sich auf ein einzelnes Thema, einen Test, einen Benchmark oder eine Beobachtung
  • Jeder Post ist auf eine Lesezeit von 5–10 Minuten ausgelegt und geht davon aus, dass JVM-Komponenten miteinander interagieren
  • Begründungen und Diskussionen können anekdotisch sein, und Fehler, Konsistenz, Stil, Grammatik und Duplikate sind möglicherweise nicht ausreichend geprüft, daher ist bei einer direkten Übernahme Vorsicht geboten
  • Das Gesamtpaket wird als ePUB, MOBI, PDF bereitgestellt; die PDF-Datei ist wegen der hochwertigen Konvertierung mehrere Dutzend MB groß
  • Der Index der einzelnen Beiträge ist in die Bereiche Compiler, Runtime, GC und Library gegliedert und behandelt interne JVM-Themen wie Lock-Optimierung, TLAB, GC-Pausen, String.intern(), Safepoint, komprimierte Referenzen und bedingte Sprünge

Annahmen beim Lesen der Serie

  • JVM Anatomy Quarks ist eine fortlaufende Mini-Post-Serie, die Grundwissen zur JVM in kurzen Texten aufbereitet
  • Jeder Post taucht tief in ein einzelnes Thema, einen Test, einen Benchmark oder eine Beobachtung ein
  • Wenn man nur einen einzelnen Post isoliert liest, kann Kontext fehlen, und die meisten behandelten Elemente interagieren leicht miteinander
  • Die Begründungen und Diskussionen in den Texten können anekdotisch sein, und Fehler, Konsistenz, Stil, Grammatik, Bedeutung und Duplikate sind möglicherweise nicht ausreichend geprüft
  • Wer die Inhalte verwendet oder ihnen vertraut, tut dies auf eigenes Risiko

Paketdateien und Indexstruktur

  • Das Gesamtpaket der Serie wird in drei Formaten bereitgestellt
    • ePUB ist am kleinsten, unter 1 MB, und basiert auf Pandoc HTML-to-ePUB
    • MOBI ist klein, im MB-Bereich, und basiert auf KindleGen ePUB-to-MOBI
    • PDF ist mit mehreren Dutzend MB sehr groß und ein qualitativ hochwertiger Output auf Basis von wkhtmltopdf HTML-to-PDF
  • Die Einzelindizes bestehen aus den Kategorien Compiler, Runtime, GC, Library

Liste der Beiträge nach Themen

  • Compiler-zentrierte Einträge

    • #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
  • Einträge, die Runtime und GC gemeinsam betreffen

    • Beiträge über Speicher- und Pausenverhalten während der JVM-Ausführung
    • #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-zentrierte Einträge

    • Fokus auf Collector-Design und Heap-Verhalten
    • #3: GC Design and Pauses
    • #11: Moving GC and Locality
    • #13: Intergenerational Barriers
    • #21: Heap Uncommit
  • Runtime-zentrierte Einträge

    • Beiträge über die JVM-Laufzeitumgebung und die Objektrepräsentation
    • #12: Native Memory Tracking
    • #23: Compressed References
    • #24: Object Alignment
    • #26: Identity Hash Code
  • Library- oder gemischte Kategorie

    • Einträge mit Library-Bezug, darunter #10: String.intern()
    • Einträge, die sowohl Compiler als auch Runtime betreffen: #16, #25, #29, #30

1 Kommentare

 
GN⁺ 2024-11-12
Meinungen auf Hacker News
  • https://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-f... ist wirklich ein bedauerlicher Fall.
    Weil einige Frameworks JNI und Reflection missbraucht haben, um final-Felder zu ändern, die eigentlich unveränderlich sein sollten, entgehen Nutzer-Code wichtige Optimierungen, die nur bei vom System bereitgestellten Klassen möglich sind.
    Plattformen, insbesondere Compiler und Runtime, müssen semantische Beschränkungen sehr strikt durchsetzen, um Spielraum für künftige Optimierungen zu bewahren.

    • Im Rahmen unserer Strategie integrity by default [1] ändern wir diesen Bereich, und ein entsprechendes JEP wird bald erscheinen.
      Es gibt tatsächlich nicht viel Code, der final ändern muss, und schon heute ist diese Arbeit auf Klassen im eigenen Modul oder auf ausdrücklich open gesetzte Klassen beschränkt. Künftig wird es daher so sein, dass eine Anwendung dem Modul, das final ändern will, die Berechtigung erteilen muss.
      Das ähnelt dem Ansatz, den wir kürzlich für native Aufrufe und unsicheren Speicherzugriff angewendet haben.
      [1]: https://openjdk.org/jeps/8305968
    • Ich frage mich, ob nicht manche durch blindes Befolgen von Effective Java die Erbsünde geschaffen haben, alles mit final zu versehen.
      Deshalb lassen sich final-Klassen in Tests heute nicht einfach mocken, und Mocking-Tools müssen sogar Bytecode-Manipulation betreiben, um final-Klassen zu mocken.
      Bei Google intern ist Effective Java zum Beispiel eine Anforderung, weshalb es auch in der öffentlichen GDrive-API final-Klassen gibt; dabei sind gerade externe APIs das, was man mocken möchte.
    • Der Fall System.out ist ein Problem von Java selbst.
      https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.htm...
      Angesichts eines solchen Präzedenzfalls ist es nicht überraschend, dass andere das für einen zulässigen Ansatz hielten.
    • Feldmodifizierer sind keine Sicherheitsbeschränkungen, sondern semantische Beschränkungen.
      Es ist richtig, dass man sie mit einem geeigneten Umgehungsverfahren umgehen können sollte.
      Der Kern ist Sicherheit, weil man durch das Ändern von Dingen, die nicht geändert werden dürfen, einen SEGV auslösen kann; genau diese Sorge sollen Zugriffsmodifizierer adressieren.
    • Ich gebe zu, dass ich vor langer Zeit in einer inzwischen verschwundenen internen Bibliothek selbst einmal einen bösartigen Dreizeiler geschrieben habe, der ein Member „un-final“ machte, es änderte und es dann wieder wie final behandelte, um ein unangenehmes Refactoring zu vermeiden.
      Ich wünschte, es wäre verhindert worden, aber es gab eine geschäftliche Anforderung.
  • Etwas anderes Thema, aber Apple hat eine neue Swift-Java-Bridge veröffentlicht, und sie ist ziemlich cool.
    Sie unterstützt sowohl JNI als auch Panama, und letzte Woche war man dabei, sie auf Android zu portieren.
    https://github.com/swiftlang/swift-java

    • Falls man das „modern“ nennen kann, ist der heutige Cross-Platform-Ansatz interessant.
      Dank Interoperabilität zwischen Sprachen kann man, wo es passt, eine Bibliothek über mehrere Plattformen hinweg teilen.
      Bisher hat man das nur mit C++ gemacht, bei Bedarf mit einer C-API davor, aber in Situationen, in denen C++ selbst nicht nötig ist, ist es natürlich nicht die bevorzugte Sprache.
      Allerdings machen mir die Kosten Sorgen. Wenn Swift in mobilen Apps problemlos Kotlin-Bibliotheken aufrufen kann, müsste eine iOS-App dann nicht in irgendeiner Form etwas JVM-Ähnliches laden? Und umgekehrt würde eine Android-App, die Swift aufruft, wohl die Swift-Runtime laden.
      Am Ende entsteht Overhead.
      Ich mache mir Sorgen, dass es irgendwann üblich wird, dass Entwickler von Swift-Bibliotheken abhängen, diese Bibliotheken wiederum von Kotlin-Bibliotheken abhängen, dafür eine JVM starten und dann über JNI wieder C++ aufrufen.
      Das ähnelt der Situation bei modernen Package-Managern: Man hat zwar nur ein paar direkte Abhängigkeiten, aber weil es „zu einfach war, um sich darum zu kümmern“, hat das Programm plötzlich über 100 transitive Abhängigkeiten.
  • Schön, dass diese gute Sammlung von Artikeln hier geteilt wurde. Durch diese Serie habe ich viel über die JVM gelernt.
    Besonders gefällt mir dieser Artikel darüber, dass der in Java häufig verwendete Ausdruck „Stack Allocation“ irreführend ist: https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacemen...
    Was die JVM tatsächlich tut, ist Escape Analysis + Scalar Replacement.

  • Mir gefällt die Länge dieser Artikel.
    Man kann einen in wenigen Minuten durchlesen und bei Interesse die Benchmarks lokal ausführen.

  • Wenn man ein paar Jahre mit JVM-basierten Sprachen gearbeitet hat, ist diese Artikelsammlung wirklich interessant.
    Ich erinnere mich noch daran, wie ich sie vor einigen Jahren zum ersten Mal gelesen habe.

  • Weiß jemand, warum der Name dieser Serie von „JVM Anatomy Park“ geändert wurde?

    • Ich vermute, der Name wurde geändert, als die Berichte über Justin Rollands Online-Verhalten erstmals bekannt wurden.
  • Java ist für mich fast in Vergessenheit geraten
    Ich käme überhaupt nicht auf die Idee, ein neues Projekt in Java zu starten.
    Wenn ich schnelle Entwicklung und Flexibilität brauche, würde ich Python wählen; wenn ich viel I/O-Concurrency mit Garbage Collection handhaben will, Go; wenn ich eine kompilierte, ausgewogene und gute Sprache brauche, Swift; und wenn ich eine kompilierte Sprache mit Performance und Sicherheit brauche, Rust.
    Das ist nur persönliche Vorliebe, und ich weiß, dass Kotlin Java angenehmer nutzbar gemacht hat, aber so fühlt es sich trotzdem an.

    • Ich bin sicher nicht der Einzige, aber vermutlich bin ich einfach in einer Situation, in der ich Java nicht brauche.
      Die wichtigsten Stärken von Java sind, dass es nahezu unbegrenzt viele Entwickler mit Java-Erfahrung gibt, dass das bestehende Library-Ökosystem riesig ist und ein erheblicher Teil davon enterprise-orientiert ist, dass sich sehr große Codebases mit vielen Beitragenden gut verwalten lassen und dass die über Jahrzehnte entwickelte Standard-VM extrem robust, ziemlich schnell und praktisch auf jeder Plattform unterstützt ist.
      Java ist nicht mehr so dominant wie Anfang der 2000er, nicht einmal im Enterprise-Bereich, und es ist die typische „Blub“-Sprache; aber wenn man Enterprise-Größe erwartet und Skalierung über viele Entwickler wichtiger ist als reine Performance, ist es eine durchaus vernünftige Wahl.
      Ich mag Rust, aber meinen Lebensunterhalt verdiene ich mit Java.
    • Ergänzend zu anderen Antworten: Java hat auch genug Eigenschaften, die Startups brauchen, sodass es für neue Projekte Sinn ergibt.
      Dank moderner Frameworks und KI-Unterstützung kann man innerhalb weniger Tage ein ordentliches Backend hochziehen.
      Als alleiniger technischer Mitgründer muss man für ein schnelles MVP im Grunde nur Java oder Kotlin sowie einen Frontend-Stack kennen; in der Praxis verbringt man ohnehin viel mehr Zeit mit Aufgaben außerhalb des Codings, wodurch Unterschiede bei Sprachfeatures weniger wichtig werden.
      Wenn es in Richtung native Mobile geht, könnte Swift die zweite Sprache werden.
      Außerdem ist es gut möglich, dass Skalierbarkeit eine Zeit lang nicht das erste Problem ist. Team-Skalierung kommt zuerst, Performance-Engpässe fallen wahrscheinlich erst deutlich später auf.
      Java eignet sich gut für große Teams.
      Wenn man aus Business-Sicht einen größeren Talentpool, schnelle Lieferzyklen und etwas will, das langfristig Teil des Kern-Stacks bleiben kann, sind Java oder Kotlin wahrscheinlich die beste Wahl.
      Go oder Rust kann man wählen, wenn man coole Technologie wie ein Benefit einsetzen will, um eine bestimmte Entwicklerschicht anzuziehen, oder wenn es einen seltenen Business-Case dafür gibt.
      Python ist in der Wissenschaft und in Bootcamps beliebt, aber sein Business-Wert für allgemeine Backends ist mir ehrlich gesagt nicht ganz klar.
    • Auf der JVM gibt es viele sehr angenehme Sprachen wie Clojure.
      Ich würde die JVM als Ganzes nicht abschreiben. Die JVM ist ein ingenieurtechnisches Meisterwerk und entwickelt sich derzeit schnell weiter. Siehe Loom, Panama, Leyden usw.
    • Um auf einen leicht entzündlichen Kommentar mit einer leicht entzündlichen Antwort zu reagieren: Java ist Go in jeder Hinsicht überlegen, und 90 % von fast allen Fällen, die du genannt hast, lassen sich mit Java abdecken.
      Deshalb ist Java für fast alles eine ziemlich klar gute Wahl.
    • Du bist sicher nicht der Einzige, aber es geht auch nicht allen so.
      Kotlin zusammen mit Java 21+ ist meine erste Wahl für I/O-lastige Dienste und im Grunde für fast jeden Dienst.
      Es ist wirklich angenehm zu nutzen, und dank virtueller Threads kann man Code schreiben, der so einfach und effizient ist wie in Go, während man gleichzeitig eines der größten und wohl besten Library-Ökosysteme der Welt nutzen kann.
      Ich will Go oder Python nicht schlechtreden. Wenn das eure bevorzugten Tools sind, sind sie völlig in Ordnung.
      Aber Java ist nicht so irrelevant geworden, wie du vielleicht denkst.