内部からjavaオブジェクトがどのように見えるか疑問に思ったことはありますか?
猫の下には、javaオブジェクトヘッダーの詳細な説明、その構成要素、および必要なメモリ量が表示されます。
まず、jvmでは、メモリ内のオブジェクトはオブジェクトヘッダーとオブジェクト変数(リンクとプリミティブ)で構成されていることを思い出してください。 また、オブジェクトの最終サイズは、サイズが8バイトの倍数になるように拡張できます。
各オブジェクトのタイトル(配列を除く)は、 mark wordとclass wordの2つの機械語で構成されます。 配列には、配列の長さを記述する追加の32ビットがあります。
マークワードには、アイデンティティハッシュコード、ガベージコレクターが使用するビット、およびロックに使用されるビットが格納されます。 詳細は、対応するOpenJDK ソートmarkOop.hppでいつでも確認できます。
クラスワードには、クラス自体へのポインター、つまり、このデータ型に関する情報が存在する場所(メソッド、注釈、継承など)へのポインターが格納されます。 詳細は、対応するOpenJDKの種類のklass.hppでも常に確認できます。
次に、オブジェクトのタイトル 、特にマークワードを詳しく見てみましょう。
32ビットJVM

表からわかるように、 Mark wordの内容は、オブジェクトの現在の状態によって大きく異なる可能性があります。
オブジェクトの通常の状態(biased_lock = 0、lock = 01)
- identity_hashcodeは、遅延して表示されるオブジェクトのハッシュです。 オブジェクトにSystem.identityHashCode(obj)呼び出しが初めてある場合、このハッシュが計算され、オブジェクトのヘッダーに書き込まれます。
他の状態では、さまざまなストリームがオブジェクトをめぐって競合する場合、identity_hashcodeはオブジェクトヘッダーではなく、オブジェクトのモニターに保存されます。 - age-経験したガベージコレクションの数。 年齢がmax-tenuring-thresholdの数に達すると、
オブジェクトは古い世代のヒップ領域に移動します。 - biased_lock-このオブジェクトに対してバイアスロックが有効になっている場合は1、それ以外の場合は0が含まれます。
もう少しバイアスロックをオンにすると、オブジェクトは、モニターをキャプチャした最初のオブジェクトに移動します。 同じストリームでのオブジェクトの後続のキャプチャは、わずかに高速になります。
このロックの基本的な理論的前提条件は次のとおりです。
- オブジェクトの存続期間中、その所有者は主に1つのストリームです。
- スレッドがこのオブジェクトのロックを最近使用した場合、プロセッサキャッシュには、このオブジェクトの再キャプチャに必要なデータがまだ含まれている可能性が高いです。
Java 6以降、バイアスロックはデフォルトで有効になっています-XX:-UseBiasedLocking
- lock-ロック状態コードが含まれています。 00-ロックされた軽量、01-ロック解除またはバイアス、10-ロックされた重量、11-ガベージコレクション用にマークされています。
つまり、テーブルでは、オブジェクトの状態は、biased_lockビットとロックビットの組み合わせによって決定されます。
バイアスロックモード(biased_lock = 1、lock = 01)
- スレッド-バイアスロックモードでは、オブジェクトは主に特定のスレッドによって所有されていると想定され、このスレッドのIDはフィールドに格納されます。
- epochには、idがthreadに格納されているスレッドによるオブジェクトの所有権の一時的なインジケーターが含まれます
軽量ロックモード(ロック= 00)
このモードでは、異なるフローによるこのオブジェクトのキャプチャ時間がまったく交差しないか、わずかに重複しないと想定されます。 このモードでは、オペレーティングシステムを大きくブロックする代わりに、JVMはアトミックを使用します。
- ptr_to_lock_record-スピンループ内のCAS(比較および設定)は、ロックの設定/待機に使用されます。
参考までに、最小OSブロッキング時間は約10ミリ秒の領域にあり、アトミックの助けを借りて、ストリームはスリープ状態に陥ることはありませんが、小さなサイクルを脱出し続けます。リソースが解放されるとすぐに、アトミックサイクルが終了し、ストリームはこのオブジェクトをすぐにキャプチャします
ヘビーウェイトロックモード(ロック= 10)
- ptr_to_heavyweight_monitor-さまざまなストリームでこのオブジェクトのキャプチャ時間が大幅にオーバーラップする場合、軽量ロックは重量ロックに置き換えられます。 モニターへのポインターがptr_to_heavyweight_monitorに書き込まれます。 OSロックが使用されます。
したがって、32ビットjvmでは、オブジェクトのヘッダーは8バイトで構成されます。 配列にはさらに4バイトがあります。
64ビットJVM

64ビットjvmでは、オブジェクトヘッダーは16バイトで構成されます。 配列にはさらに4バイトがあります。
ポインター圧縮を備えた64ビットJVM

オブジェクトヘッダーは12バイトで構成されます。 配列にはさらに4バイトがあります。
ポインター圧縮について少し。 32ビットポインターの場合、アドレススペースは4GBに制限されます。 ただし、jvmでオブジェクトのサイズが8バイトの倍数であることを再度思い出すと、最後に3つのゼロがある擬似35ビットポインターを使用できます。 したがって、すでに32GBのメモリを参照しています。 圧縮は無料ではなく、価格はヒープへの呼び出しに対する追加の操作(ポインター<< 3)です。
元の記事へのリンク:
Javaオブジェクトヘッダー
また、ここで説明するすべてがドグマではないことを付け加えます。おそらく、jvmの他のバージョンでは、オブジェクトのタイトルが異なります。 ここで説明するのは、openjdk 8に関連するものです。