JVMの深い理解==>ランタイムデータ領域

1. JVMの概要

  JVMはJava Virtual Machine(Java Virtual Machine)の略で、コンピューティングデバイスの仕様であり、実際のコンピュータでさまざまなコンピュータ機能をシミュレートすることによって実現される架空のコンピュータです。

  Java言語の非常に重要な機能は、そのクロスプラットフォームの性質です。この機能を実現するには、Java仮想マシンを使用することが重要です。一般的な高水準言語を異なるプラットフォームで実行する場合は、少なくとも異なるオブジェクトコードにコンパイルする必要があります。Java言語仮想マシンの導入後は、異なるプラットフォームで実行するときにJava言語を再コンパイルする必要はありません。Java言語はJava仮想マシンを使用して特定のプラットフォームに関連する情報をシールドするため、Java言語コンパイラは、Java仮想マシンで実行され、変更なしで複数のプラットフォームで実行できるターゲットコード(バイトコード)を生成するだけで済みます。 。Java仮想マシンがバイトコードを実行すると、そのバイトコードは特定のプラットフォームで実行するためのマシン命令として解釈されます。これが、Javaが「一度コンパイルすればどこでも実行できる」理由です。

2、JVMメモリ管理モデル

ヒープメモリ(ヒープ)

  ほとんどのアプリケーションでは、Javaヒープは、Java仮想マシンによって管理される最大のメモリです。Javaヒープは、すべてのスレッドで共有され、仮想マシンの起動時に作成されるメモリ領域です。このメモリ領域の唯一の目的は、ほとんどすべてのオブジェクトインスタンスにメモリが割り当てられるオブジェクトインスタンスを格納することです。

  Javaヒープメモリは、若い世代と古い世代に細分することもできます。その中で、若い世代はEdenエリア、From Survivorスペース、To Survivorスペースなどに分類できます。

  ヒープにインスタンス割り当てを完了するためのメモリがなく、ヒープが拡張できなくなった場合、OutOfMemoryError例外がスローされます。

メソッドエリア

  メソッド領域(メソッド領域)は、Javaヒープと同様に、さまざまなスレッドによって共有されるメモリ領域です。仮想マシンによって読み込まれた、リアルタイムコンパイラによってコンパイルされたクラス情報、定数、静的変数、コードなどのデータを格納するために使用されます。Java仮想マシン仕様では、メソッド領域はヒープの論理部分として記述されていますが、Non-Heap(非ヒープ)と呼ばれるエイリアスがあり、Javaヒープとは区別する必要があります。

  HotSpot仮想マシンでのプログラムの開発と展開に慣れている開発者にとって、多くの人々はメソッド領域を「Permanent Generation」と呼んでもかまいません。本質的に、HotSpot仮想マシンの理由から、2つは同等ではありません設計チームは、GC生成コレクションをメソッド領域に拡張するか、永続的な生成を使用してメソッド領域を実装することを選択しました。

  Java仮想マシンの仕様では、この領域に非常に緩やかな制限があります。連続メモリを必要とせず、固定または拡張可能なJavaヒープに加えて、ガベージコレクションを実装しないことも選択できます。比較的言えば、この領域ではガベージコレクションの動作は比較的まれですが、永続的な世代の名前として「永続的に」存在するため、データがメソッド領域に入るわけではありません。この領域でのメモリ回復の目的は、主に定数プールの回復と型のアンロードですが、一般的に言えば、この領域の回復の「達成」は、特にアンロードの種類では満足できません。リサイクルは確かに必要です。

  Java仮想マシン仕様によると、メソッド領域がメモリ割り当ての要件を満たせない場合、OutOfMemoryError例外がスローされます。

プログラムカウンター(プログラムカウンターレジスター)

  プログラムカウンター(プログラムカウンターレジスタ)は小さなメモリ空間であり、その機能は現在のスレッドによって実行されるバイトコードの行番号インジケーターと見なすことができます。仮想マシンの概念モデル(概念モデルのみ、さまざまな仮想マシンがより効率的な方法で実装されている場合があります)では、バイトコードインタープリターは、このカウンターの値を変更して、次に実行する仮想マシンを選択することによって機能します。バイトコード命令、分岐、ループ、ジャンプ、例外処理、スレッド回復、およびその他の基本機能はすべて、完了するためにこのカウンターに依存する必要があります。

  Java仮想マシンのマルチスレッドはスレッド切り替えとプロセッサ実行時間の割り当てによって実装されるため、任意の時点で、プロセッサ(マルチコアプロセッサの場合、コア)は1つのスレッドのみを実行します。手順。したがって、スレッドの切り替え後に正しい実行位置を復元するには、各スレッドに独立したプログラムカウンターが必要です。各スレッド間のカウンターは相互に影響せず、独立して保存されます。このタイプのメモリ領域を「スレッドプライベート」と呼びます「メモリ。

  スレッドがJavaメソッドを実行している場合、このカウンターは実行中の仮想マシンのバイトコード命令のアドレスを記録し、Natvieメソッドが実行されている場合、カウンター値は空です。

  このメモリ領域は、Java仮想マシン仕様でOutOfMemoryErrorを指定していない唯一の領域です。

Java仮想マシンスタック(JVMスタック)

  プログラムカウンターと同様に、Java仮想マシンスタック(Java仮想マシンスタック)もスレッド専用であり、そのライフサイクルはスレッドと同じです。仮想マシンスタックは、Javaメソッド実行のメモリモデルを記述します。各メソッドが実行されると、ローカル変数テーブル、操作スタック、ダイナミックリンク、メソッド出口、およびその他の情報を格納するためのスタックフレーム(Stack Frame)が同時に作成されます。各メソッドは、実行が完了するまで呼び出されます。これは、スタックから仮想マシンスタック内のスタックへのスタックフレームに対応します。

  ローカル変数テーブルには、さまざまな仮想マシンに応じて、さまざまな基本データ型(ブール、バイト、文字、短、整数、浮動小数点、長整数、倍精度浮動小数点数)、オブジェクト参照(オブジェクト自体とは異なる参照型)が格納されます実装。これは、オブジェクトの開始アドレスへの参照ポインタである場合があります。また、オブジェクトまたはオブジェクトに関連する他の場所を表すハンドルを指す場合があります)およびreturnByteタイプ(バイトコード命令のアドレスを指す)。

  その中で、64ビットのlongおよびdoubleタイプのデータは2つのローカル変数スペース(スロット)を占有し、残りのデータタイプは1スロットのみを占有します。ローカル変数テーブルに必要なメモリ空間は、コンパイル時に割り当てられます。メソッドに入ると、メソッドがフレームに割り当てる必要があるローカル変数空間の量が完全に決定されます。ローカル変数テーブルのサイズは、メソッド中に変更されません。

  Java仮想マシン仕様では、この領域に2つの例外条件が指定されています。スレッドによって要求されたスタックの深さが仮想マシンで許可されている深さより大きい場合、StackOverflowError例外がスローされます。仮想マシンスタックを動的に拡張できる場合(現在のJava仮想マシンのほとんどは動的に拡張できますが、Java仮想マシンの仕様では固定長の仮想マシンスタックも許可されています)、拡張時に十分なメモリを適用できない場合にスローされます。 OutOfMemoryError例外。

ネイティブメソッドスタック

  ネイティブメソッドスタック(ネイティブメソッドスタック)と仮想マシンスタックは非常によく似た役割を果たします。違いは、仮想マシンスタックが仮想マシンに対してJavaメソッド(つまり、バイトコード)サービスを実行するのに対し、ローカルメソッドスタックは仮想マシンによって使用されるネイティブメソッドサービス。ローカルメソッドスタック内のメソッドの言語、使用法、およびデータ構造は、仮想マシン仕様では必須ではないため、特定の仮想マシンが自由に実装できます。一部の仮想マシン(Sun HotSpot仮想マシンなど)は、ローカルメソッドスタックと仮想マシンスタックを直接1つに結合します。仮想マシンスタックと同様に、StackOverflowErrorおよびOutOfMemoryError例外がローカルメソッドスタック領域でスローされます。

ランタイム定数プール

  定数プールはメソッド領域の一部です。クラスファイルのクラスバージョン、フィールド、メソッド、インターフェイス、およびその他の説明情報に加えて、コンパイラによって生成されたさまざまなリテラルおよびシンボル参照を格納するために使用される定数プールもあります。コンテンツのこの部分は、クラスが読み込まれた後、メソッド領域の実行時定数プールに格納されます。

  ランタイム定数プールの重要な機能はその動的な性質です。Java言語では、コンパイル時にのみ定数を生成する必要はありません。つまり、クラスファイルの定数プールの内容は、メソッド領域のランタイム定数プールに入るように事前設定されていません。期間中、新しい定数を定数プールに入れることもできますこの機能は、開発者がよく使用するStringクラスのintern()メソッドです。

  定数プールは実行時にメソッド領域の一部であるため、メソッド領域のメモリによって当然制限されます。定数プールがメモリに適用できない場合、OutOfMemoryError例外がスローされます。

直接記憶

  ダイレクトメモリは、仮想マシンのランタイムデータ領域の一部ではなく、Java仮想マシン仕様で定義されているメモリ領域でもありません。ただし、メモリのこの部分も頻繁に使用され、OutOfMemoryErrorを引き起こす可能性があるため、ここで紹介します。

  JDK1.4では、NIO(新しい入力/出力)クラスが新たに追加され、チャネルとバッファに基づくI / Oメソッドが導入されました。ネイティブ関数ライブラリを使用してオフヒープメモリを直接割り当てることができます。 Javaヒープに格納されているDirectByteBufferオブジェクトは、このメモリへの参照として使用され、Javaヒープとネイティブヒープ間でデータがコピーされないようにします。これにより、一部のシナリオでパフォーマンスが大幅に向上します。

  直接メモリ割り当ては、Javaヒープメモリによって制限されませんが、マシンの合計メモリサイズとプロセッサのアドレス空間によって制限されます。仮想マシンのパラメーターを設定するとき、サーバー管理者は実際のメモリに応じて-Xmsや-Xmxなどのパラメーター情報を設定しますが、多くの場合ダイレクトメモリを無視するため、各メモリ領域の合計が物理メモリの制限よりも大きくなり、動的拡張中にOutOfMemoryError例外が発生します。

おすすめ

転載: www.cnblogs.com/L-Test/p/12736914.html