JVM 実行時の 5 つの主要なデータ領域の詳細な説明

 序文:

        Java 仮想マシンは Java プログラムを実行する際、自身が所有するメモリ領域をいくつかのデータ領域に分割します。これらの領域にはさまざまな機能があり、それぞれの任務を実行します。これらのエリアは機能が異なるだけでなく、生成と破壊の時間も異なります。一部の領域はスレッドプライベートです。たとえば、各スレッドには独自のプログラム カウンタがあり、プログラム カウンタはユーザー スレッドの作成時に作成され、スレッドが破棄されるときに破棄されます。また、ヒープがすべてのスレッドで共有されるなど、一部の領域はすべてのスレッドで共有されます。「Java 仮想マシンの仕様」によれば、Java 仮想マシンによって管理されるメモリには、次の実行時データ領域が含まれます。

 注: JVM は仕様の集合であると言えます。

5つの分野についてそれぞれ詳しく紹介していきます。 

1. プログラムカウンター (スレッド分離)

        プログラム カウンタは小さなメモリ空間です。その機能は、このスレッドの次の命令の位置を記録することです。Java仮想マシンのマルチスレッドは、スレッドを順番に切り替えてプロセッサの実行時間を割り当てることで実現します。マルチスレッドでは、割り当てられたタイムスライスの実行後にスレッドが切り替わりますが、実行後にスレッドが切り替わることは保証できません(タイムスライスのサイズは不確かです)。スイッチバック後にスレッドを正しい実行位置に確実に復元できるようにするため。したがって、次の命令のアドレスを記録するプログラム カウンターが必要です。スレッドが CPU を取り戻したら、プログラム カウンターに移動して次の命令のアドレスを取得し、実行を継続します。これがプログラムの主な機能です。カウンター。したがって、各スレッドには、互いに独立した独自のプログラム カウンターが必要です。したがって、プログラム カウンターはスレッドに対してプライベートです。

        要約すると、これはプログラム制御フローの指標であり、分岐、ループ、ジャンプ、例外処理、スレッド回復などの基本機能はすべて、完了するためにこのプログラム カウンターに依存する必要があります。

2.Java仮想マシンスタック(スレッド分離)

        仮想マシン スタックは、プログラム カウンターと同様にスレッド プライベートであり、対応するスレッドと同じライフ サイクルを持ちます。仮想マシン スタックは、ローカル変数テーブル、オペランド スタック、ダイナミック リンク、メソッド リターンなどの情報を格納するためのスタック フレーム (スタック フレーム) を内部に格納します。各メソッドは、実行の開始から終了までのスタック フレームを表し、仮想マシン スタックにプッシュされ、スタックからポップアウトされます。仮想マシン実行時のメソッド呼び出しとメソッド実行のデータ構造であり、仮想スタックの基本要素です。

        基本的なデータ型のデータとオブジェクト参照は、スタック フレームのローカル変数テーブルに格納されます。この基本型は確かにスタック フレームに格納されており、ここに格納されているオブジェクト参照は実際のオブジェクトではなく、オブジェクトの開始アドレスを指す参照ポインタであるか、オブジェクトなどを指すハンドルである可能性があります。このオブジェクトに対する相対的な位置。

        ローカル変数テーブルにおけるこれらのデータの格納空間のサイズは、ローカル変数スロット(Slot)によって表される。2 つの変数スロットを占有する double 型とlong 型のデータを除き、他のデータ型は 1 つの変数スロットを占有します。したがって、このメソッドが必要とするローカル変数スペースの量は、このメソッドを呼び出した直後に決定されます。ローカル変数テーブルのサイズは、メソッドの実行中に変更されません。

このデータ領域には 2 つの例外が指定されています。

  • StackOverflowError 例外: スレッド アプリケーションのスレッドの深さが Java 仮想マシンで許可されている深さよりも大きい場合、この例外が報告されます。
  • OutOfMemoryError 例外: この例外は、仮想マシン スタックを動的に拡張できる場合に、仮想マシン スタックに十分な深さを適用できない場合に報告されます。

3. ローカル メソッド スタック (スレッド分離)

        この領域は仮想マシンのスタックに似ています。2 つの違いは、仮想マシン スタックは仮想マシンの Java (つまり、バイトコード) メソッドを実行するのに対し、ローカル メソッド スタックは仮想マシンのローカル (非 Java) メソッドを実行することです。仮想マシン スタックとネイティブ メソッド スタックを 1 つに組み合わせた仮想マシンもあります。仮想マシン スタックと同様に、ローカル メソッド スタックも、スタックの深さがオーバーフローしたり、スタックの拡張が失敗したりすると、StackOverflowError 例外と OutOfMemoryError 例外をスローします。

4.Javaヒープ(スレッド共有)

        ヒープは、JVM の最大のメモリ領域です。ヒープとは、すべてのスレッドで共有される領域で、オブジェクトの作成と破棄はガベージコレクタによって自動的に管理されます。仮想マシンの起動時に作成されます。このメモリ領域の唯一の目的はオブジェクト インスタンスを保存することであり、Java 世界の「ほぼ」すべてのオブジェクト インスタンスがここにメモリを割り当てます。ただし、ヒープ上にない場合もまだいくつかあります。

  1. メソッドのインライン最適化: 場合によっては、コンパイラーはメソッドのインライン最適化を実行し、メソッド呼び出しをメソッド本体のコードに直接置き換えます。この最適化により、オブジェクト インスタンスをヒープではなくスタック上に作成できるようになります。この場合、オブジェクト インスタンスのライフサイクルは比較的短い可能性があります。

  2. スレッドプライベートオブジェクト: 一部のオブジェクトは 1 つのスレッドによってのみ所有され、他のスレッドからはアクセスされません。このようなオブジェクトはスタック上に割り当てることができるため、より効率的なメモリ アクセスが可能になります。

        Java ヒープは固定サイズまたは拡張可能なヒープとして実装できますが、現在主流の Java 仮想マシンはすべてスケーラビリティの観点から実装されています。Java ヒープにインスタンスの割り当てを完了するためのメモリがない場合、ヒープは展開できない場合、Java 仮想マシンは OutOfMemoryError 例外をスローします。

5. メソッド領域(スレッド共有)

実はメソッド領域はJDK1.8以前のバージョンから存在したメモリ領域で、主にクラスファイルからロードされたクラスを格納しており、定数プールもこの領域にあります。

しかし、JDK1.8以降、この領域は名称が変更され、「Metaspace」(直訳すると「メタスペース」)となりましたが、もちろん名前が変わっただけで、実装されている機能は変わりません。

メソッド領域(メソッド領域)は、Javaヒープと同様に各スレッドが共有するメモリ領域で、インスタントコンパイラで読み込まれた型情報、定数、静的変数、コンパイルされたコードキャッシュなどのデータを格納するために使用されます。仮想マシン。

5.1 型情報

ロードされた型 (クラス クラス、インターフェイス インターフェイス、列挙 enum、アノテーション annotation) ごとに、JVM は次の型情報をメソッド領域に格納する必要があります。 ① この型の完全かつ有効な名前 (フルネーム = パッケージ名.クラス名
)
②このタイプの直接の親クラスの完全な実効名 (インターフェイスまたは
Javaの場合
。シーケンス リスト)

5.2 ドメイン情報(フィールド)メンバ変数

JVM は、ある型のすべてのフィールドに関する情報と、フィールドがメソッド領域で宣言される順序を保存する必要があります。
ドメイン関連情報には、ドメイン名、ドメイン タイプ、ドメイン修飾子 (パブリック、プライベート、保護、静的、最終、揮発性、一時的なサブセット) が含まれます。

5.3 メソッド情報

JVM は、すべてのメソッドに関する次の情報と、宣言順序を含むドメイン情報を保存する必要があります。

  • メソッド名
  • メソッドの戻り値の型 (または void) メソッドのパラメータの数と型 (順序)
  • メソッド修飾子 (public、private、protected、static、final、synchronized、native、abstract のサブセット)
  • メソッドのバイトコード(バイトコード)、オペランドスタック、ローカル変数テーブルとサイズ(抽象メソッドとネイティブメソッドを除く)

おすすめ

転載: blog.csdn.net/qq_64680177/article/details/132232210