JVM(10)-Javaオブジェクト作成プロセスとメモリ割り当て戦略

1つは、Javaオブジェクトの作成プロセスです。

最初のステップ:クラスの読み込みチェック

仮想マシンが新しい命令を検出すると、この命令のパラメーターが定数プール内のこのクラスのシンボル参照を見つけることができるかどうかを確認し、このクラスがロード、接続、および初期化されているかどうかを確認します。完了し、直接戻るこのオブジェクトは問題ありません。そうでない場合は、次の手順に進みます。

ステップ2:メモリを割り当てる

クラスロードチェックに合格すると、仮想マシンは新しいオブジェクトをオブジェクトに割り当てます。オブジェクトのメモリサイズは、クラスロードの完了後に決定できます。オブジェクトにスペースを割り当てるタスクは、特定のオブジェクトを分割することと同じです。ヒープへのメモリのサイズが出てきます。ポインタの衝突とフリーリストの2つの割り当て方法があります。これらの2つの方法を使用するためのルールは、現在のメモリスペースが完全であるかどうか、およびヒープスペースが完全であるかどうかを判断することです。アルゴリズムが使用されます。

マーククリアアルゴリズムはメモリの断片化を生成し、メモリスペースが不完全になります。マークデフラグまたはコピーアルゴリズムを使用してもメモリの断片化は生成されないため、スペースは規則的です。

  • ポインタの衝突:通常のヒープメモリに適しています。ヒープメモリが通常の場合、一方が使用済みメモリ、もう一方がスペースメモリです。中央に境界インジケータとしてポインタがあります。メモリの割り当ては、ポインタを自由方向に移動します。mobile
  • フリーリスト:メモリが不規則な状況に適用できます。つまり、メモリの使用済みスペースと空きスペースがインターリーブされます。これには、使用可能なメモリを記録するためのリストを維持する必要があります。オブジェクトにメモリを割り当てるときは、「十分に検索」を検索してください。リスト内の領域を更新してから、リストを更新します

メモリを割り当てるときにスレッドセーフを確保するにはどうすればよいですか?

メモリを割り当てるときにスレッドを確保するには、次の2つの方法があります。

  • CAS + Failure Retry:メモリを割り当てるアクションに対してアトミック操作を実行し、CASメカニズムを使用して更新操作のアトミック性を確保します
  • TLAB:ヒープはスレッドによって共有される領域であると前述しましたが、ヒープ内には非常に特殊なスペースがあります。TLABは、ヒープ上のスレッドによって排他的に占有される領域です。メモリを割り当てるときは、最初にTLABに割り当てることができます。オブジェクトのスペースがTLABより大きい場合、またはTLABのスペースが不十分な場合、CAS +失敗の再試行のメソッドがヒープ上の共有スペースに割り当てられます。

ステップ3:ゼロ値を初期化します

メモリの割り当てが完了したら、割り当てられたメモリスペースを値0に初期化する必要がありますが、オブジェクトヘッダーは含まれません。この手順は、クラスの読み込みメカニズムで説明されています。ゼロの値を初期化すると、静的変数とクラスインスタンス変数が保証されます。表示されません。指定された値も使用できます。

ステップ4:オブジェクトヘッダーを設定する

ゼロ値の初期化が完了したら、オブジェクトに必要な設定が必要です。これは、オブジェクトヘッダーを設定するためです。オブジェクトヘッダーには、通常、データの2つの側面が格納されます。

  • ハッシュコード、GC生成マーク、ロックステータスなどの独自の操作情報は、マークワークとも呼ばれます。
  • タイプポインタ、そのクラスのメタデータへのオブジェクトポインタ
  • 配列の長さ。オブジェクトが配列の場合のみ、これはオプションのフィールドです。

ステップ5:initメソッドを実行します

上記の作業が完了すると、JVMにはオブジェクトが作成されたように見えますが、initメソッドがまだ実行されておらず、すべてのフィールドがまだ0であるため、プログラマーにとっては終了していません。したがって、initメソッドはここで実行する必要があります。

第二に、オブジェクトのメモリ割り当て戦略

オブジェクトのメモリ割り当て戦略は、ガベージの世代別コレクションに基づいています。世代別アルゴリズムに従って、ヒープは新世代と旧世代に分割されます。新世代には、エデン領域、フォーム領域、および宛先領域があります。 、では、オブジェクトはどこで作成および割り当てられますか?注文は何ですか?

まず、オブジェクトは最初にエデンエリアに割り当てられます。エデンエリアに割り当てるスペースがない場合、仮想マシンはマイナーGCを開始してエデンエリアをガベージコレクションします。マイナーGCが実行された後、エデンエリアはまだ収まりません。オブジェクト、オブジェクトは、いわゆる大きなオブジェクトである古い時代に直接置かれます。古い時代がまだオブジェクトを置くことができない場合、OOMは直接報告されます。

マイナーGCでは、エデンエリアのオブジェクトをクリーンアップし、エデンエリアの生き残ったオブジェクトをフロムエリアに保管すると同時に、フロムエリアにゴミがあるかどうか、必要かどうかを判断します。ゴミがある場合はリサイクルされ、残りのオブジェクトは再びtoゾーンに移動し、これらのオブジェクトの年齢カウントを1増やします。しばらくすると、一部のオブジェクトは15に達します(このしきい値は次のように設定できます)。パラメータ)、次にこれらのオブジェクトを古い時代に移動します。

第三に、オブジェクトアクセス場所の方法

上記は、Javaがオブジェクトを作成するプロセスとメモリを割り当てる方法、およびそれに応じてそれにアクセスする方法を説明していますか?参照は、Java仮想マシンスタックのスタックフレームに格納されます。Java仮想マシンの仕様では、ヒープ上のこれらのオブジェクトを見つけてアクセスするためにこの参照を使用する方法は定義されていません。一般的に、ハンドルとハンドルの2つの方法があります。直接ポインタ。

3.1ハンドル

handleメソッドを使用する場合、メモリの一部はハンドルプールとしてJavaヒープに分割されます。オブジェクトのハンドルアドレスは参照に格納され、ハンドルにはオブジェクトインスタンスデータとタイプの特定のアドレス値が含まれます。データ。

ここに写真の説明を書いてください

3.2ダイレクトポインタ

直接ポインタは、ローカル変数テーブルに格納されているJavaヒープ内のオブジェクトのアドレスを参照します

ここに写真の説明を書いてください

2つのアクセス方法は異なります。ハンドルを使用する最大の利点は、参照が安定したハンドルアドレスを格納することです。オブジェクトが移動されると、ハンドル内のインスタンスデータポインタのみが変更され、参照を変更する必要がありません。 。

安定したハンドルアドレスは誤って保存されます。オブジェクトが移動されると、ハンドル内のインスタンスデータポインタのみが変更され、参照を変更する必要はありません。

ダイレクトポインタ方式を使用する最大の利点は、アクセス速度が速く、ポインタの位置決め時間を渡す必要がないことです。

おすすめ

転載: blog.csdn.net/weixin_44706647/article/details/115207952