Haben Sie sich jemals gefragt, wie Java-Objekte von innen aussehen?
Unter der Katze finden Sie eine detaillierte Beschreibung des Java-Objekt-Headers, woraus er besteht und wie viel Speicher er benötigt.
Denken Sie zunĂ€chst daran, dass in jvm jedes Objekt im Speicher aus dem Objektheader und den Objektvariablen (Links und Grundelemente) besteht. AuĂerdem kann die endgĂŒltige GröĂe des Objekts auf ein Vielfaches von 8 Bytes erweitert werden.
Der Titel jedes Objekts (mit Ausnahme des Arrays) besteht aus zwei Maschinenwörtern - Markierungswort und Klassenwort . Arrays haben zusÀtzliche 32 Bit, um die LÀnge des Arrays zu beschreiben.
Markierungswort speichert IdentitĂ€ts-Hashcode, vom Garbage Collector verwendete Bits und fĂŒr Sperren verwendete Bits. Weitere Details finden Sie immer in den entsprechenden OpenJDK- Sortierungen markOop.hpp .
Ein Klassenwort speichert einen Zeiger auf die Klasse selbst, dh auf die Stelle, an der sich die Informationen zu diesem Datentyp befinden: Methoden, Anmerkungen, Vererbung und mehr. Weitere Details finden Sie auch immer in den entsprechenden OpenJDK- Sorten von klass.hpp .
Schauen wir uns nun den Titel des Objekts genauer an und markieren Sie insbesondere das Wort
32 Bit JVM

Wie Sie der Tabelle entnehmen können, kann der Inhalt des Markierungsworts je nach aktuellem Status des Objekts stark variieren.
Normalzustand des Objekts (Biased_lock = 0, Lock = 01)
- identity_hashcode ist der Hash eines Objekts, das trÀge erscheint. Wenn das Objekt zum ersten Mal einen System.identityHashCode (obj) -Aufruf hat, wird dieser Hash berechnet und in den Objektheader geschrieben.
In anderen ZustĂ€nden, wenn verschiedene Streams um ein Objekt konkurrieren, wird identity_hashcode nicht im Objektheader, sondern auf dem Objektmonitor gespeichert. - Alter - die Anzahl der erlebten MĂŒllsammlungen. Wenn das Alter die maximale Dauer erreicht,
Das Objekt bewegt sich in den HĂŒftbereich der alten Generation. - biased_lock - enthĂ€lt 1, wenn die voreingenommene Sperre fĂŒr dieses Objekt aktiviert ist, andernfalls 0.
Ein bisschen mehrWenn die voreingenommene Verriegelung aktiviert ist, bewegt sich das Objekt sozusagen zum ersten Objekt, das seinen Monitor erfasst hat. Die anschlieĂende Erfassung des Objekts im selben Stream ist etwas schneller.
Hier sind die grundlegenden theoretischen Voraussetzungen fĂŒr dieses Schloss:
- WĂ€hrend der gesamten Lebensdauer eines Objekts befindet es sich ĂŒberwiegend im Besitz eines Streams
- Wenn der Thread kĂŒrzlich eine Sperre fĂŒr dieses Objekt verwendet hat, enthĂ€lt der Prozessor-Cache höchstwahrscheinlich immer noch die Daten, die zum erneuten Erfassen dieses Objekts erforderlich sind.
Das voreingenommene Sperren ist standardmĂ€Ăig aktiviert, da Java 6, -XX: -UseBiasedLocking
- lock - enthĂ€lt den Sperrstatuscode. 00 - Leicht verriegelt, 01 - Entriegelt oder vorgespannt, 10 - Schwergewicht verriegelt, 11 - FĂŒr die MĂŒllabfuhr markiert.
Das heiĂt, in der Tabelle wird der Zustand eines Objekts durch die Kombination der Bits Biased_lock und Lock bestimmt.
Biased Locked-Modus (Biased_lock = 1, Lock = 01)
- Thread - Im voreingenommenen Sperrmodus wird davon ausgegangen, dass das Objekt ĂŒberwiegend einem bestimmten Thread gehört. Die ID dieses Threads wird im Feld gespeichert.
- Die Epoche enthĂ€lt einen temporĂ€ren Indikator fĂŒr den Besitz des Objekts durch einen Thread, dessen ID im Thread gespeichert ist
Leichter gesperrter Modus (Sperre = 00)
In diesem Modus wird angenommen, dass sich die Erfassungszeit dieses Objekts durch verschiedene FlĂŒsse ĂŒberhaupt nicht ĂŒberschneidet oder nicht unwesentlich ĂŒberlappt. In diesem Modus verwendet die JVM Atomics, anstatt das Betriebssystem stark zu blockieren.
- ptr_to_lock_record - CAS (Vergleichen und Setzen) innerhalb der Spin-Schleife wird zum Setzen / Warten auf eine Sperre verwendet.
Als Referenz wird die minimale OS-Blockierungszeit im Bereich von ungefÀhr 10 ms liegen, mit Hilfe von Atomics, der Stream schlÀft nicht ein, sondern drescht weiterhin einen kleinen Zyklus, und sobald die Ressource frei ist, endet der Atomzyklus und der Stream erfasst dieses Objekt sofort.
Schwergewichts-Sperrmodus (Sperre = 10)
- ptr_to_heavyweight_monitor - Wenn sich die Erfassungszeit dieses Objekts mit verschiedenen Streams erheblich ĂŒberschneidet, wird die leichte Sperre durch eine schwere Sperre ersetzt. Ein Zeiger auf den Monitor wird in ptr_to_heavyweight_monitor geschrieben. Die Betriebssystemsperre wird verwendet.
In 32-Bit-JVM besteht der Header des Objekts aus 8 Bytes. Arrays haben zusÀtzlich 4 Bytes.
64 Bit JVM

Auf einem 64-Bit-JVM besteht der Objektheader aus 16 Bytes. Arrays haben zusÀtzlich 4 Bytes.
64-Bit-JVM mit Zeigerkomprimierung

Ein Objektheader besteht aus 12 Bytes. Arrays haben zusÀtzlich 4 Bytes.
Ein bisschen ĂŒber die Zeigerkomprimierung. Bei einem 32-Bit-Zeiger ist der Adressraum auf 4 GB begrenzt. Wenn wir uns jedoch noch einmal daran erinnern, dass in jvm die GröĂe eines Objekts ein Vielfaches von 8 Bytes ist, können wir einen Pseudo-35-Bit-Zeiger mit drei Nullen am Ende verwenden. Und beziehen sich daher bereits auf 32 GB Speicher. Die Komprimierung ist nicht kostenlos, der Preis ist eine zusĂ€tzliche Operation (Zeiger << 3) fĂŒr jeden Aufruf von Heap.
Link zum Originalartikel:
Java-Objekt-Header
Ich möchte auch hinzufĂŒgen, dass alles, was hier beschrieben wird, kein Dogma ist, vielleicht wird in anderen Versionen von jvm der Titel des Objekts anders sein. Hier beschrieben ist relevant fĂŒr openjdk 8.