Java仮想マシンオブジェクトの作成プロセスと初期化プロセス

序文

オブジェクト作成プロセスと初期化プロセスを整理します

Java仮想マシンのランタイムデータ領域

オブジェクト作成プロセス

オブジェクトの作成

  1. 新しい命令を使用する場合は、定数プールで命令のパラメーターのシンボル参照を見つけます
  2. そうでない場合は、クラスをロード、接続、および初期化します。
  3. 仮想マシンは、新生児オブジェクトにメモリを割り当てます
  4. オブジェクトヘッダーを除いて、割り当てられたメモリスペースをゼロに初期化し、オブジェクトヘッダー(ハッシュコード、gc ageなど)を初期化します。
  5. オブジェクトメソッドを呼び出す

1.クラスの読み込みプロセス

Java仮想マシンの詳細な理解第7章仮想マシンクラスのロードのタイミングとプロセス

2.オブジェクトメモリのレイアウト

メモリ内のオブジェクトのレイアウトは、オブジェクトヘッダー、インスタンスデータ、および配置パディングの3つの領域に分けられます。

1.オブジェクトヘッド

Hotspot仮想マシンのオブジェクトヘッダーには、主に2つのデータ部分が含まれます。MarkWord(マークされたフィールド)とKlass Pointer(タイプポインター)。配列は、配列の長さを格納するために1ワード幅(32ビット:4バイト)になります。 。

  • Mark Wordは、オブジェクト自体のランタイムデータを格納するために使用されます。これは、軽量ロックとバイアスロックを実現するための鍵です。
  • Klass Pointは、オブジェクトのクラスメタデータへのポインターであり、仮想マシンはこのポインターを使用して、オブジェクトがどのクラスインスタンスであるかを判別します。

2.サンプルデータ

この部分は、オブジェクトが実際に格納する有効な情報であり、親クラスから継承されたものやサブクラスで定義されたものなど、プログラムコードで定義されたさまざまなタイプのフィールドのコンテンツでもあります。

3.位置合わせして塗りつぶします

この部分は必要ありません。一部の仮想マシンでは、オブジェクトの開始アドレスが8バイトの整数倍である必要があります。つまり、オブジェクトのサイズは8バイトの整数倍である必要があるため、次の場合は位置合わせが必要です。不十分。

4.マークワードの詳細な説明

JVMのオブジェクトヘッダーには2つの方法があります(例として32ビットJVMを取り上げます)。

// 普通对象
|--------------------------------------------------------------|
|                     Object Header (64 bits)                  |
|------------------------------------|-------------------------|
|        Mark Word (32 bits)         |    Klass Word (32 bits) |
|------------------------------------|-------------------------|

// 数组对象
|---------------------------------------------------------------------------------|
|                                 Object Header (96 bits)                         |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(32bits)       |    Klass Word(32bits) |  array length(32bits)  |
|--------------------------------|-----------------------|------------------------|
  • Mark Wordの
    この部分は、主に、ハッシュコード、gc生成期間、ロックステータスフラグ、スレッドによって保持されているロック、バイアスされたスレッドID、バイアスされたタイムスタンプなど、オブジェクト自体のランタイムデータを格納するために使用されます。
    マークワードのビット長は、JVMの1ワードのサイズです。つまり、32ビットJVMのマークワードは32ビットであり、64ビットJVMは64ビットです。
    Mark Wordは、非常に小さなメモリスペースにできるだけ多くのデータを格納するための非固定データ構造として設計されています。オブジェクトの状態に応じて独自のストレージスペースを再利用します。ワードサイズでより多くの情報を格納するために、 JVMはワードの下位2ビットをマークビットとして設定し、異なるマークビットの下のマークワードは次のように表示されます。
|-------------------------------------------------------|--------------------|
|                  Mark Word (32 bits)                  |       State        |
|-------------------------------------------------------|--------------------|
| identity_hashcode:25 | age:4 | biased_lock:0 |lock:01 |     Normal无锁      |
|-------------------------------------------------------|--------------------|
|  thread:23 | epoch:2 | age:4 | biased_lock:1| lock:01 |     Biased偏向锁    |
|-------------------------------------------------------|--------------------|
|               ptr_to_lock_record:30         | lock:00 | Lightweight Locked轻量级锁 |
|-------------------------------------------------------|--------------------|
|               ptr_to_heavyweight_monitor:30 | lock:10 | Heavyweight Locked重量级锁 |
|-------------------------------------------------------|--------------------|
|                                             | lock:11 |    Marked for GC   GC标记|
|-------------------------------------------------------|--------------------|

ロック状態

  • lock:2ビットのロックステータスフラグビット。できるだけ多くの情報を表すためにできるだけ少ないバイナリビットを使用するため、ロックフラグが設定されます。マークの値が異なり、マークワード全体の意味が異なります。
  • biased_lock:オブジェクトがバイアスロックフラグを有効にするかどうか。バイアスロックフラグは1バイナリビットしか占有しません。1の場合、オブジェクトにバイアスロックがあることを意味します。0の場合、オブジェクトにバイアスロックがないことを意味します。
  • 年齢:4桁のJavaオブジェクトの年齢。GCでは、オブジェクトがサバイバーエリアに1回コピーされると、年齢が1増加します。被験者が設定されたしきい値に達すると、老年期に昇格します。デフォルトでは、パラレルGCの経過時間しきい値は15であり、並行GCの経過時間しきい値は6です。ageは4ビットしかないため、最大値は15です。これが、-XX:MaxTenuringThresholdオプションの最大値が15である理由です。
  • identity_hashcode:遅延読み込みテクノロジーを使用した25ビットのオブジェクト識別ハッシュコード。System.identityHashCode()メソッドを呼び出して、結果を計算し、オブジェクトヘッダーに書き込みます。オブジェクトがロックされると、値はモニターモニターに移動されます。
  • thread:バイアスロックを保持しているスレッドのID。
  • エポック:バイアスタイムスタンプ。
  • ptr_to_lock_record:スタック内のロックレコードへのポインタ。
  • ptr_to_heavyweight_monitor:モニターをモニターするためのポインター。

3.オブジェクトの初期化シーケンス

クラスのロードプロセスに従って、最初にクラスの初期化clinitが実行され、次にオブジェクトの初期化initメソッドが実行されます。シーケンスは次のとおりです。

  1. 親クラスの静的変数
    サブクラスの静的変数

  2. 親クラスの静的
    コードブロック子クラスの静的コードブロック

  3. 親クラスメソッドブロック
    親クラスコンストラクタ

  4. サブクラスメソッドブロック
    サブクラスコンストラクタ

3.オブジェクトアクセス場所

現在、アクセスするには2つの主流の方法があります。

  • ハンドルに
    は、ハンドルプールとしてヒープとは別のメモリが必要ですが、GCによってオブジェクトが移動されると、参照に安定したハンドルアドレスが格納され、ハンドル内のインスタンスポインタのみが変更されるという利点があります。
    扱う

  • ダイレクトポインタには
    高速であるという利点があります
    直接ポインタアクセス

これにより、仮想マシンスタック(スタックフレーム内のローカル変数テーブル)で参照されているオブジェクトがGCルートで何を参照しているかがわかります。

結論

この記事では、オブジェクト作成の一般的なプロセスを整理します。これは、仮想マシンを理解するのに非常に役立ちます。

おすすめ

転載: blog.csdn.net/u014099894/article/details/105968386