RU | EN | DE

JVM-Architektur — kurz und prägnant

Class Loader Subsystem

Die JVM lädt Klassen mithilfe eines Systems von Class Loadern, das ein Delegationsmodell implementiert:

  • Bootstrap ClassLoader – lädt Standardklassen aus dem JDK (rt.jar oder JDK-Module).
  • Extension ClassLoader – lädt Bibliotheken aus dem ext-Verzeichnis.
  • Application ClassLoader – lädt Klassen aus dem Classpath.
  • Der Benutzer kann einen Custom ClassLoader für dynamisches Laden erstellen (z.B. in OSGi, Plugins).

Runtime Data Areas

  • Heap – Bereich, in dem alle Objekte leben.
  • Method Area (Metaspace) – enthält Metainformationen von Klassen, Konstanten-Pool.
  • JVM Stack – wird pro Thread erstellt, enthält Methoden-Aufruf-Frames.
  • Program Counter Register (PC Register) — ist ein kleiner Zeiger, der die Nummer des nächsten Befehls speichert, den der Thread ausführen soll.
  • Native Method Stack – Stack für native Methodenaufrufe.

Execution Engine

  • Interpreter – schrittweise Interpretation von Bytecode.
  • JIT Compiler (Just-In-Time) – kompiliert häufig verwendete Methoden in Maschinencode.
  • GC Interface – Die Execution Engine ist eng mit dem Garbage Collector verbunden: Sie muss wissen, wann ein Objekt nicht mehr verwendet wird, und den Speicher korrekt freigeben.

Delegation Model

Delegation Model (Delegationsmodell von ClassLoadern) — ist ein Mechanismus, mit dem die JVM Klassen in einer strikten Reihenfolge von oben nach unten lädt, um Konflikte und Duplikate zu vermeiden.

Wenn ein ClassLoader eine Klasse laden möchte, delegiert er diese Aufgabe zunächst an seinen Eltern-ClassLoader, und nur wenn der Eltern-ClassLoader die Klasse nicht gefunden hat, lädt er sie selbst.

JVM-Speicherverwaltung

In der JVM ist der Speicher in mehrere Bereiche unterteilt, und jeder hat seine eigene Rolle

  • Heap (Haufen)
    • Hier werden Objektinstanzen gespeichert.
    • Für jedes Objekt wird Platz für seine Felder (Daten) zugewiesen.
    • Referenzen auf Objekte werden ebenfalls erstellt, aber diese Referenzen werden normalerweise im Stack gespeichert oder in Feldern anderer Objekte im Heap.
  • Stack (Stapel)
    • Hier werden lokale Methodenvariablen gespeichert, einschließlich Referenzen auf Objekte im Heap.
    • Wenn die Methode die Ausführung beendet, wird ihr Frame aus dem Stack entfernt.
  • Metaspace (Metabereich)
    • Hier werden Klassen und ihre Struktur gespeichert: Methoden, Konstanten, Informationen über Felder.
    • Speichert keine Objektinstanzen selbst

Heap

  • Young Generation: o Eden – neue Objekte. o Survivor Spaces (S0/S1) – Zwischenzonen.
  • Old Generation – Objekte, die mehrere Sammlungen in Young Gen überlebt haben.

Stack

Jeder Thread hat seinen eigenen Stack, bestehend aus Methoden-Aufruf-Frames. In jedem Frame werden gespeichert:

  • lokale Methodenvariablen,
  • Operanden-Stack für Zwischenberechnungen,
  • Referenz auf den Konstanten-Pool der Klasse, um Konstanten und Methoden dieser Klasse zu verwenden.

Metaspace

  • Was gespeichert wird: Informationen über Klassen — ihre Metadaten, Methoden, Konstanten, Annotationen.
  • Unterschied zu PermGen: In Java 8+ wurde PermGen entfernt, und Metaspace wird im nativen Speicher gespeichert, nicht im Heap. Dies ermöglicht es der JVM, den Raum für Metadaten dynamisch zu erweitern, ohne ein hartes Limit (wenn nicht -XX:MaxMetaspaceSize gesetzt ist).
  • Wachstum und Limits: wächst mit dem Laden neuer Klassen; kann über JVM-Parameter begrenzt werden (MaxMetaspaceSize, MetaspaceSize).

Off-heap Memory

Dies ist Speicher, der außerhalb des Standard-Heaps der JVM direkt im nativen Speicher zugewiesen wird.

  • Beispiele:
    • ByteBuffer.allocateDirect() — direkter Puffer für die Arbeit mit nativem Speicher, umgeht GC.
    • Native Ressourcen-Pools, Caching großer Daten.
  • Gefahren:
    • Die JVM verfolgt diesen Speicher nicht, daher sind Lecks möglich.
    • Unsachgemäße Speicherfreigabe (DirectByteBuffer) kann zu OutOfMemoryError führen, selbst wenn der Heap leer ist.

Constant pool

Constant Pool — ist ein spezieller Ort in den Klassenmetadaten (Teil der Method Area in der JVM), wo Konstanten, Literale und Referenzen auf Methoden/Klassen gespeichert werden.

Das heißt, der Constant Pool ist wie ein Schrank mit fertigen Dingen, und der Stack ist ein Tisch, auf dem man sie zum Arbeiten auslegt.

Garbage collector (GC)

GC - Mechanismus der JVM, der automatisch Speicher freigibt, der von Objekten belegt wird, auf die keine Referenzen mehr bestehen.

In modernen JVMs kann ein Garbage Collector verschiedene Algorithmen für verschiedene Speicherbereiche verwenden:

  • Copying (kopierend) — wird in Young Generation angewendet. Er kopiert schnell lebende Objekte in einen neuen Speicherbereich, und alles andere wird als Müll betrachtet.
  • Mark-Sweep-Compact (markieren-aufräumen-kompaktieren) — wird häufiger in Old Generation angewendet. Zuerst werden lebende Objekte markiert (Mark), dann wird Müll entfernt (Sweep), und die verbleibenden werden kompaktiert (Compact), um Fragmentierung zu vermeiden.

GC-Typen

Serial GC

  • Verwendet einen Thread für alle GC-Phasen.
  • Geeignet für Single-Thread-Anwendungen und kleine Heaps.
  • Algorithmus: “copying” (in Young Gen) und “mark-sweep-compact” (in Old Gen).
  • Parameter: -XX:+UseSerialGC

Parallel GC (Throughput Collector)

  • Verwendet mehrere Threads für die Arbeit in Young und Old Gen.
  • Ziel — maximaler Durchsatz, nicht Minimierung von Pausen.
  • Geeignet für Serveranwendungen ohne strenge Latenzanforderungen.
  • Parameter: -XX:+UseParallelGC

CMS (Concurrent Mark Sweep) [veraltet]

  • Arbeitet parallel zur Anwendung (concurrent), reduziert Stop-the-World-Pausen.
  • Phasen: initial mark, concurrent mark, remark, sweep.
  • Kompaktiert den Speicher nicht (kann zu Fragmentierung führen).
  • Veraltet ab Java 9 und entfernt in Java 14
  • Parameter: -XX:+UseConcMarkSweepGC

G1 GC (Garbage First)

  • Teilt den Heap in viele Regionen auf.
  • Jede Region kann Teil von Young oder Old Generation sein.
  • GC-Phasen umfassen: Initial Mark, Concurrent Mark, Remark, Cleanup, Copy.
  • Arbeitet nach dem Prinzip “Sammlung zuerst der müllreichsten Regionen” (Garbage First).
  • Verwendet vorhersagbare Pausen und versucht, MaxGCPauseMillis nicht zu überschreiten
  • Unterstützt inkrementelle, concurrent und kompaktierende Sammlung von Old Gen.
  • G1 führt Statistiken über die “Nützlichkeit” von Regionen und wählt die effektivsten für die Sammlung.
  • Parameter: -XX:+UseG1GC
  • Standardmäßig verwendet ab Java 9+

ZGC (Z Garbage Collector)

  • Unterstützt Heaps bis zu Terabytes.
  • Arbeitet mit Pausen von weniger als 10 ms, unabhängig von der Heap-Größe.
  • Vollständig concurrent (fast alle Phasen werden parallel zur Anwendung ausgeführt).
  • Geeignet für latency-sensitive Systeme.
  • Parameter: -XX:+UseZGC

Shenandoah

  • Ähnlich wie ZGC, mit Fokus auf kurze Pausen.
  • Verwendet concurrent compacting.
  • Unterstützt von OpenJDK.
  • Parameter: -XX:+UseShenandoahGC

Welcher GC ist Standard in Java

Java-VersionStandard-GC
java 8Parallel GC
java 9+G1 GC

Einige JDKs (z.B. Azul Zulu) können standardmäßig ZGC oder Shenandoah verwenden, wenn spezifische Latenz-Ziele gesetzt sind

Pausen

  • Stop-the-world – bei einigen GC-Phasen werden alle Threads angehalten.
  • Minor GC – in Young Generation.
  • Major/Full GC – in Old Generation, kann die Bereinigung von Metaspace einschließen.

Performance und Tuning

  • -Xms / -Xmx – minimale/maximale Heap-Größe.
  • -Xss – Stack-Größe pro Thread.
  • -Xss – Stack-Größe pro Thread.
  • -XX:+PrintGCDetails, -Xlog:gc

JIT (Just-In-Time) Kompilierung

  • Die JVM interpretiert zunächst Bytecode, aber häufig ausgeführte Methoden werden während der Programmlaufzeit in nativen Maschinencode kompiliert.
  • Ermöglicht eine Beschleunigung der Ausführung durch Vermeidung ständiger Interpretation.
  • Optimierungen
    • Inlining — die Methode wird “in den aufrufenden Code eingebettet”, um die Overhead-Kosten des Methodenaufrufs zu eliminieren.
    • Escape Analysis — analysiert, ob das Objekt die Methode/den Thread verlässt; wenn nicht — kann das Objekt im Stack statt im Heap platziert werden, was die Belastung des GC reduziert.

Class Loading und Reflection

Delegation Model

Der ClassLoader delegiert zunächst das Laden an den Eltern-ClassLoader und versucht erst dann, selbst zu laden.

Custom ClassLoaders

Werden benötigt für:

  • Plugins
  • modulare Systeme (OSGi, Spring Boot)
  • Hot-Reloading von Code

Reflection

Reflection ermöglicht dynamisches Arbeiten mit Klassen und ihren Mitgliedern, Erstellen von Proxies, verlangsamt aber die Ausführung und kann die Kapselung verletzen. SecurityManager kann solche Operationen einschränken.

Referenztypen in Java

Strong Reference (starke Referenz)

  • Dies sind normale Referenzen, die wir jeden Tag verwenden.
  • Solange mindestens eine starke Referenz auf das Objekt existiert — ist es nicht für Garbage Collection geeignet.
  • Damit das Objekt gesammelt werden kann, müssen alle starken Referenzen darauf auf null gesetzt werden.
Object obj = new Object();

Soft Reference (weiche Referenz)

  • Das Objekt wird nur bei Speichermangel gelöscht.
  • Wird in Caches verwendet, um keinen Speicher zu verbrauchen, aber das Objekt zu behalten, wenn es noch nützlich ist.
  • Man kann das Objekt über ref.get() erhalten, aber wenn GC es bereits gelöscht hat — wird null zurückgegeben.
SoftReference<Object> ref = new SoftReference<>(new Object());

Weak Reference (schwache Referenz)

  • Das Objekt kann sofort gesammelt werden, selbst wenn nur schwache Referenzen darauf verbleiben.
  • Wird verwendet für die Implementierung von Strukturen mit automatischer Löschung (z.B. WeakHashMap).
  • Wird oft angewendet, wenn das Objekt verfügbar sein sollte “solange es jemand braucht”.
WeakReference<Object> ref = new WeakReference<>(new Object());

Phantom Reference (Phantom-Referenz)

  • Das Objekt ist bereits zum Löschen markiert, aber noch nicht vom GC gesammelt.
  • Die Methode get() gibt immer **null** zurück.
  • Wird verwendet für Kontrolle der Finalisierung und Freigabe von Ressourcen außerhalb des Heaps (z.B. off-heap, native).
  • Erfordert ReferenceQueue, über die man erfahren kann, dass das Objekt bald gelöscht wird.
PhantomReference<Object> ref = new PhantomReference<>(new Object(), referenceQueue);

Fazit

Heute haben wir die Schlüsselaspekte der JVM, die Speicherverwaltung und Garbage Collection behandelt, die am häufigsten in Java-Interviews vorkommen. Natürlich wird nicht unbedingt alles aus dieser Liste gefragt, aber damit können Sie diese Themen sicher diskutieren und werden definitiv nicht verwirrt sein.