詳細なJVM(1)
表示する前のヒント:
この記事では、ZhouZhimingの「Java仮想マシンの詳細な理解」について説明します。
1はじめに
JVMはJavaVirtual Machine(Java Virtual Machine)の略です。JVMはコンピューティングデバイスの仕様です。実際のコンピューターでさまざまなコンピューター機能をシミュレートすることによって実現される架空のコンピューターです。
Java言語仮想マシンの導入後、異なるプラットフォームで実行する場合、Java言語を再コンパイルする必要はありません。Java言語はJava仮想マシンを使用して特定のプラットフォームに関連する情報を保護するため、Java言語コンパイラはJava仮想マシンで実行されるオブジェクトコード(バイトコード)を生成するだけでよく、変更なしで複数のプラットフォームで実行できます。 。
2.ランタイムデータ領域
Java仮想マシンは、Javaプログラムの実行中に、管理するメモリをいくつかの異なるデータ領域に分割します。次の図に示すように、Java仮想マシンによって管理されるメモリには、次のランタイムデータ領域が含まれます。
2.1プログラムカウンター
プログラムカウンタは小さなメモリスペースであり、その機能は、現在のスレッドによって実行されるバイトコードの行番号インジケータとして見ることができます。仮想マシンの概念モデルでは、バイトコードインタープリターが機能すると、このカウンターの値を変更して、実行する次のバイトコード命令を選択します。分岐、ループ、ジャンプ、例外処理、スレッド回復などの基本機能。完了するには、このカウンターに依存する必要があります。
Java仮想マシンのマルチスレッド化は、スレッドがプロセッサの実行時間を交互に切り替えて割り当てる方法によって実現されるため、ある時点で、プロセッサは1つのスレッドでのみ命令を実行できます。したがって、スレッド切り替え後に正しい実行位置に復元するには、各スレッドに独立したプログラムカウンターが必要です。スレッド間のカウンターは相互に影響を与えず、独立して格納されます。このタイプのメモリ領域を「スレッドプライベート」と呼びます。メモリ。
スレッドがJavaメソッドを実行している場合、このカウンターは実行されている仮想マシンのバイトコード命令のアドレスを記録します。スレッドがネイティブメソッドを実行している場合、このカウンター値は空(未定義)です。このメモリ領域は、Java仮想マシン仕様でOutOfMemoryError条件を指定しない唯一の領域です。
スレッドはプライベートであり、メモリスペースは小さいです。
仮想マシンのバイトコード命令アドレスを格納するか、空(未定義)にします。
OutOfMemoryError例外はありません。
2.2Java仮想マシンスタック
プログラムカウンターと同様に、Java仮想マシンスタックはスレッド専用であり、そのライフサイクルはスレッドのライフサイクルと同じです。仮想マシンスタックは、Javaメソッド実行のメモリモデルを記述します。各メソッドが実行されると、同僚は、ローカル変数テーブル、操作スタック、動的リンク、メソッド出口などの情報を格納するスタックフレームを作成します。各メソッドが呼び出されてから実行が完了するまでのプロセスは、このスタックフレームが仮想マシンスタックにプッシュされてポップされるまでのプロセスに対応します。
ローカル変数テーブルには、基本的なデータタイプ(boolean、byte、char、short、int、float、long、double)、オブジェクト参照(参照タイプ)、およびreturnAddressタイプ(バイトコード命令を指す)が格納されます。住所)。
スレッドはプライベートであり、ライフサイクルはスレッドのライフサイクルと同じです。
ローカル変数テーブル、操作スタック、動的リンク、メソッド出口、およびその他の情報を格納します。
スレッドによって要求されたスタックの深さは、仮想マシンによって許可された深さよりも大きく、StackOverflowError例外がスローされます。仮想マシンを動的に拡張できる場合、拡張が十分なメモリを適用できないと、OutOfemoryError例外がスローされます。
2.3ローカルメソッドスタック
ネイティブメソッドスタックと仮想マシンスタックが果たす役割は非常に似ています。違いは、仮想マシンスタックが仮想マシンにJavaメソッドの実行を提供し、ローカルメソッドスタックが仮想マシンによって使用されるネイティブメソッドにサービスを提供することです。
ネイティブメソッドを保存します。
仮想マシンスタックと同様に、StackOverflowErrorおよびOutOfMemoryError例外もスローされます。
2.4Javaヒープ
ほとんどのアプリケーションでは、Javaヒープは、Java仮想マシンによって管理される最大のメモリです。Javaヒープは、すべてのスレッドで共有されるメモリ領域であり、仮想マシンの起動時に作成されます。このメモリ領域の唯一の目的はオブジェクトインスタンスを格納することであり、ほとんどすべてのオブジェクトインスタンスがここにメモリを割り当てます。この点は、Java仮想マシンの仕様で説明されています。すべてのオブジェクトインスタンスと配列はヒープに割り当てる必要がありますが、JITコンパイラの開発とエスケープ分析手法の段階的な成熟に伴い、スタック割り当てとスカラー置換最適化手法は微妙な変化が発生し、すべてのオブジェクトがヒープに割り当てられ、徐々に「絶対的」ではなくなります。
メモリ回復の観点から、現在のコレクターは基本的に世代別収集アルゴリズムを使用しているため、Javaヒープは、新世代と旧世代に細分することもできます。より詳細なものには、Edenスペース、From Survivorスペース、サバイバースペースなどへ メモリ割り当ての観点から、スレッドによって共有されるJavaヒープは、複数のスレッドプライベート割り当てバッファー(スレッドローカル割り当てバッファー、TLAB)に分割できます。
スレッド共有、最大のメモリ。
オブジェクトインスタンスと配列を保存します。
強度の割り当てを完了するためのメモリがヒープになく、ヒープを拡張できない場合、OutOfMemoryError例外がスローされます。
2.5メソッド領域
メソッド領域は、Javaヒープと同様に、各スレッドで共有されるメモリ領域であり、クラス情報、定数、静的変数、仮想マシンによってロードされたジャストインタイムコンパイラによってコンパイルされたコードなどのデータを格納するために使用されます。この領域はヒープの論理的な部分として記述されていますが、Non-Heapと呼ばれるエイリアスがあり、現時点ではJavaヒープと区別する必要があります。
スレッド共有
クラス情報、定数、静的変数、仮想マシンによってロードされたジャストインタイムコンパイラによってコンパイルされたコードなどのデータを格納します。
メソッド領域がメモリ割り当て要件を満たすことができない場合、OutOfMemoryError例外がスローされます。
2.6ランタイム定数プール
実行時定数プールはメソッド領域の一部です。クラスファイル内のクラスバージョン、フィールド、メソッド、およびインターフェイスの説明情報に加えて、定数プールもあります。コンパイラによって生成されたさまざまなリテラルおよびシンボル参照を格納するために使用されます。コンテンツのこの部分は、クラスがロードされた後、メソッド領域の実行時定数プールに格納されます。
コンパイラによって生成されたさまざまなリテラルとシンボル参照を格納します。
定数プールがメモリに適用できなくなると、OutOfMemoryError例外がスローされます。
2.7ダイレクトメモリ
ダイレクトメモリは、実行中の仮想マシンのデータ領域の一部ではなく、Java仮想マシンで定義されたメモリ領域でもありませんが、メモリのこの部分も頻繁に使用され、OutOfMemoryErrorを引き起こす可能性があります。
明らかに、ローカルダイレクトメモリの割り当てはJavaヒープのサイズによって制限されませんが、メモリであるため、泥棒はマシンの合計メモリ(RAMとSWAP領域またはページングファイルを含む)とプロセッサのアドレス指定スペースの影響を確実に受けます。制限。
仮想マシンの実行中は、データ領域の一部ではありません。
各メモリ領域の合計が物理メモリ制限を超えているため、動的拡張中にOutOfMemoryError例外が発生します。
3.オブジェクトアクセス
主流のアクセス方法は2つあります。ハンドルとダイレクトポインタの使用です。
3.1ハンドルアクセスを使用する
ハンドルアクセス方式を使用する場合、メモリの一部はハンドルプールとしてJavaヒープに分割されます。オブジェクトのハンドルアドレスは参照に格納され、ハンドルにはオブジェクトインスタンスデータとタイプデータの特定のアドレスが含まれます。
利点:安定したハンドルアドレスが参照に保存され、オブジェクトが移動します(ガベージコレクション中にオブジェクトを移動することは非常に一般的な動作です)ハンドルのインスタンスデータポインタのみを変更します、および参照自体を変更する必要はありません
3.2ダイレクトポインタアクセスを使用する
ダイレクトポインタアクセス方式を使用する場合、Javaヒープオブジェクトのレイアウトでは、関連する残りのアクセスタイプデータを配置する方法を考慮する必要があります。オブジェクトアドレスは、参照に直接格納されます。
利点:より速く、ポインタの位置決めの時間コストを節約しますJavaではオブジェクトアクセスが非常に頻繁に行われるため、このタイプのオーバーヘッドも非常に大きな実行コストになります。