JVMアーキテクチャのランタイムデータ領域

1.Javaランタイムデータの違いを簡単に説明します

 

PCレジスタ/プログラムカウンタ

厳密に言えば、現在実行中のプログラムのメモリアドレスを保存するためのデータ構造です。Javaはマルチスレッド実行をサポートしているため、プログラム実行の軌跡は必ずしも線形実行とは限りません。複数のスレッドを横方向に実行する場合は、現在中断しているスレッドのプログラムを実行しているメモリアドレスを保存して、中断したスレッドが実行を再開したときに、中断した命令アドレスに従って実行し続けるようにする必要があります。スレッド切り替え後に正しい実行位置に復元するには、各スレッドに独立したプログラムカウンタが必要です。各スレッド間のカウンタは相互に影響を与えず、独立して格納されます。このタイプのメモリ領域を「スレッドプライベート」と呼びます。メモリ。これは、ある意味で「ThreadLocal」にいくぶん似ており、スレッドセーフです。


Java栈Javaスタック

Javaスタックは常にスレッドに関連付けられています。スレッドが作成されるたびに、JVMはスレッドに対応するJavaスタックを作成します。このJavaスタックには複数のスタックフレームが含まれます。これらのスタックフレームは各メソッドに関連付けられ、スタックフレームは次のようになります。メソッドが実行されるたびに作成され、各スタックフレームには、ローカル変数、操作スタック、メソッドの戻り値などの情報が含まれます。メソッドが実行されるたびに、スタックフレームは、メソッドの戻り値としてスタックフレームの要素をポップアップし、スタックフレームをクリアします。Javaスタックの最上位のスタックフレームは、現在実行されているアクティブなスタックです。つまり、現在実行中のメソッドであるPCレジスタもこのアドレスを指します。操作スタックは、このアクティブなスタックフレームのローカル変数のみを使用できます。このスタックフレームで別のメソッドが呼び出されると、それに対応する新しいスタックフレームが作成され、この新しく作成されたスタックフレームがJavaスタックに配置されます。スタックの最上位が現在アクティブなスタックになります。また、このスタックのローカル変数のみを使用できるようになりました。このスタックフレーム内のすべての命令が完了すると、このスタックフレームはJavaスタックから削除され、前のスタックフレームがアクティブなスタックフレームになり、前のスタックフレームの変更このスタックフレームの操作スタックのオペランドです。

Javaスタックはスレッドに対応しているため、Javaスタックデータはスレッドによって共有されないため、データの整合性を気にする必要はなく、同期ロックの問題も発生しません。

Java仮想マシンの仕様では、この領域に2つの異常な条件が指定されています。スレッドによって要求されたスタックの深さが仮想マシンによって許可された深さよりも大きい場合、StackOverflowError例外がスローされます。仮想マシンを動的に拡張できる場合、拡張を適用できない場合十分なメモリがある場合、OutOfMemoryErrorがスローされます。ホットスポット仮想マシンでは、-Xssパラメーターを使用してスタックサイズを設定できます。スタックのサイズは、関数呼び出しの到達可能な深さを直接決定します。

 

ヒープ

概念

ヒープは、JVMによって管理される最大のメモリです。すべてのJavaスレッドロックによって共有され、スレッドセーフではありません。JVMの起動時に作成されます。ヒープは、Javaオブジェクトが格納される場所です。これは、Java仮想マシンの仕様で説明されています。すべてのオブジェクトインスタンスと配列は、ヒープに割り当てる必要があります。JavaヒープはGC管理の主要な領域です。メモリリカバリの観点から、GCは基本的に世代収集アルゴリズムを使用するため、Javaヒープは次のように細分化することもできます:新世代と旧世代;新世代はEden Space、From Survivor space、To Survivorspaceなどでより詳細に説明します。


メソッドエリア

概念

メソッド領域はヒープの一部であり、通常、Javaヒープでは永続領域(永続生成)と呼ばれます。サイズはパラメーターで設定できます。初期値は-XX:PermSizeで指定できます。最大値は値は-XX:MaxPermSizeで指定できます。

メソッド領域には、ロードするクラスの情報(名前、修飾子など)、クラスの静的定数、クラスのfinalとして定義された定数、クラスのフィールド情報、およびクラスのメソッド情報が格納されます。渡されるとプログラム内ClassオブジェクトのgetName.isInterfaceなどのメソッドを使用して情報を取得する場合、これらのデータはすべてメソッド領域から取得されます。

メソッド領域はJavaスレッドロックによって共有されます。Javaヒープの他の部分とは異なり、GCによって頻繁にリサイクルされます。格納される情報は比較的安定しており、特定の条件下ではGCになります。メソッド領域がより多くのメモリを使用する場合サイズが大きい場合、OutOfMemoryエラーメッセージがスローされます。

コンスタントプール

定数プール自体は、メソッド領域のデータ構造です。定数プールには、文字列、最終変数値、クラス名、メソッド名などの定数が格納されます。

定数プールはコンパイル中に決定され、コンパイルされた.classファイルに保存されます。

一般的に2つのカテゴリに分けられます:

リテラル:文字列、最終変数など。

引用:クラス名とメソッド名は引用に属します。最も一般的なのは、メソッドを呼び出すときにメソッド名に基づいてメソッド参照を見つけ、これを関数本体として使用して関数コードを実行することです。参照ボリュームには、クラスとインターフェースの権限名、フィールドの名前と記述子、およびメソッドの名前と記述子が含まれます。

 

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

ネイティブメソッドスタックとJavaスタックが果たす役割は非常に似ています。違いは、JavaスタックがJVMにJavaメソッドを実行するのに対し、ネイティブメソッドスタックはJVMにネイティブメソッドを実行することです。ネイティブメソッドスタックは、StackOverflowErrorおよびOutOfMemoryError例外もスローします。

2.JVMメモリモデルJMM

なぜそのようなモデルが分割されるのでしょうか?
コードを実行するとオブジェクトのライフサイクルが異なるため、ヒープ内で3世代に分割され、gc割り当てのサイズによって、3世代のサイズが異なります。実際には回避する必要があります。スペースを無駄にする

1.8以降、メタスペースが永続世代に置き換わりました(永続世代のメモリが不十分であるか、メモリリークが発生することがよくありますが、例外java.lang.OutOfMemoryError :)、メタスペースはメモリに存在し、サイズは可変です(ArrayListと同様)。欠点は次のとおりです。メタスペースが無期限に拡張すると、メモリ内の他のリソーススペースを占有し、メモリオーバーフローが発生します。

3.どのようなオブジェクトがgcになりますか

判定アルゴリズム
参照カウント方式:オブジェクトが参照されている場合は、オブジェクト内でカウントされます。オブジェクトが使用されていない場合は、カウントが0になり、リサイクルされます。循環参照(つまり、AはBを参照し、BはAを参照)に遭遇すると、時間内に相互に参照せず、リサイクルできません。これが、アルゴリズムが最終的にgcによって削除された理由でもあります。

到達可能性分析:gcRootによっては、gcルートがオブジェクトを指していない場合にオブジェクトがリサイクルされます。gcRootになる可能性のあるオブジェクトは次のとおりです。①仮想マシンスタックのローカル変数テーブルによって参照されるオブジェクト;②メソッド領域のクラス静的変数によって参照されるオブジェクト③メソッド領域の定数によって参照されるオブジェクト;④ローカルメソッドのjniによって参照されるオブジェクト。理由:①④スレッド実行時に存在している必要があり、②③は常に存在します。

では、到達不能なものは回収されますか?必ずしもそうではありませんが、finalize()は、失われた参照オブジェクトに再び到達可能にすることができますが、調整できるのは1回だけです。

 

おすすめ

転載: blog.csdn.net/shenyuye/article/details/108075114