1.JVM の構成#
- クラスローダー:.class ファイルを JVM メモリにロードする
- 実行時データ領域:プログラムカウンタ、仮想マシンスタック、ネイティブメソッドスタック、メソッド領域、ヒープで構成される
- 実行エンジン:JVM 命令を解析し、マシンコードに変換し、解析が完了したらオペレーティングシステムに送信する
- ネイティブライブラリインターフェース:さまざまな開発言語のネイティブライブラリを統合したもので、Java から呼び出すためのもの
- ネイティブメソッドライブラリ:Java ネイティブメソッドの具体的な実装
2. クラスローダー#
2.1 分類
- ブートストラップクラスローダー:ネイティブメソッドクラスをロードする
- 拡張クラスローダー:JDK 内部の拡張クラスをロードする
- システムクラスローダー:プログラムのクラスファイルをロードする
2.2 親子委譲メカニズム
クラスファイルを JVM メモリにロードする際、サブクラスローダーはロードリクエストを親クラスローダーにディスパッチし、親クラスローダーが最初にロードを試みます。親クラスローダーがクラスファイルをロードできない場合、サブクラスローダーがロードします。
システムクラスローダー拡張クラスローダーブートストラップクラスローダー
3. 実行エンジン#
3.1 変換#
- ジャストインタイムコンパイラ:プログラム内のホットスポットコードに対して、ジャストインタイムコンパイラは対応するマシンコードを保存し、同じコードに遭遇した場合に保存されたマシンコードを使用して置き換えます。
- バイトコードインタプリタ:バイトコードをマシンコードに解釈します。
4. 実行時データ領域#
4.1 ヒープ#
4.1.1 構成要素
- 新生代:eden、survivor(to、from)の 2 つの領域を含む
- 老年代
4.1.2 ガベージコレクションメカニズム
ガベージとは何か
- 参照カウント法:各オブジェクトに参照値を割り当て、オブジェクトが参照される回数を表します。循環参照の問題が発生する可能性があります。
- 可達性解析:gc ルートから下方向にトラバースし、トラバースされなかったオブジェクトはガベージです。
gc ルートには、仮想マシンスタックのスタックフレームが参照するローカル変数、ネイティブメソッドスタックの参照するローカル変数、メソッド領域のクラスの静的変数、メソッド領域の定数プール内の変数、および synchronized ロックオブジェクトが含まれます。
ガベージを回収する方法
マークアンドスイープアルゴリズム、マークアンドコピー、マークアンドコンパクト、世代ごとのガベージコレクションアルゴリズム
分類
新生代ガベージコレクタ:シリアル、パラレルニュー、パラレルスカベンジ
老年代ガベージコレクタ:シリアルオールド、パラレルオールド、CMS
ミックス:G1
ガベージコレクションを開始するタイミング
- ヤング GC
ヤングジェネレーションの eden 領域がいっぱいになったときにトリガーされます。注意点として、ヤング GC では一部の生存オブジェクトがオールドジェネレーションに昇格するため、ヤング GC 後、オールドジェネレーションの使用量が通常よりも高くなることに注意してください。 - メジャー GC
オールドジェネレーション領域が一定の閾値に達したときに実行されます。(通常、CMS のみがメジャー GC を実行する?) - フル GC
- 大きなオブジェクトを作成し、Eden 領域に収まらない場合、直接オールドジェネレーションに保存されます。オールドジェネレーションのスペースも不足している場合、フル GC がトリガーされます。
- メタスペースがいっぱいになった場合、フル GC がトリガーされます。
- メモリを回収するために System.gc()を呼び出します。
CMS
- 三色マーキング法
- 主なフロー
- 初期マーク:stw、gc ルートとヤング領域から直接参照されるオブジェクト(つまり、gc ルート自体)をマークします。
- 並行マーク:stw せずに、グレーにマークされたオブジェクトをトラバースし、トラバースされたオブジェクトをグレーにマークし、エントリポイントオブジェクトをブラックにマークします。
- 並行プリパレーション:stw せずに、並行マーク中に生成されたダーティカードを処理します。
- 再マーク:stw、SATB ライトバリアのオブジェクト参照を処理し、グレーにマークされたオブジェクトを再度マークします。
- 並行クリア:stw せずに、すべてのホワイトオブジェクトをクリアします。
- 欠点
- CPU リソースを占有する
- フローティングガベージ:並行クリアフェーズ中にユーザーがガベージを生成し続けるため、次の gc でクリアする必要があります
- メモリフラグメンテーション:CMS はマークアンドスイープアルゴリズムを採用しているため、大量のメモリフラグメンテーションが発生します
- 並行失敗:フローティングガベージの存在のため、CMS は新しく生成されたガベージを格納するために一部のスペースを予約する必要があります。CMS は、Old 領域の 68%を使用するときにアクティブ化され、フローティングガベージを格納するために 32%のスペースを予約します。これは比較的保守的な設定です。実際の参照では、Old 領域の成長が速くない場合は、
-XX:CMSInitiatingOccupancyFraction
パラメータを適切に調整してこの値を高くすることができます。JDK6 では、トリガーの閾値が 92%に引き上げられ、フローティングガベージを格納するために 8%のスペースが予約されました。 CMS が予約したメモリにフローティングガベージを格納できない場合、 "並行失敗" が発生し、JVM はバックアッププランをトリガーし、Serial Old ガベージコレクタを使用して Old 領域を回収します。この場合、停止時間が長くなります。
G1
- リージョン
G1 は、ヒープスペース全体を同じサイズのメモリ領域であるリージョンに分割するアプローチを採用しています。オブジェクトの割り当て時には、メモリを段階的に使用します。したがって、G1 ではオブジェクトの格納が物理的に連続している必要はありません。論理的に連続していれば十分です。各リージョンは、特定の世代に対してサービスを提供する必要はなく、若年世代と老年世代の間で必要に応じて切り替えることができます。起動時に、パラメータ - XX:G1HeapRegionSize = n を使用してリージョンのサイズ(1MB〜32MB、2 のべき乗である必要があります)を指定することができます。デフォルトでは、ヒープ全体が 2048 のリージョンに分割されます。
G1 では、特別な領域である Humongous 領域も存在します。オブジェクトが領域の容量の 50%以上を占める場合、G1 ガベージコレクタはそれを巨大なオブジェクトと見なします。これらの巨大なオブジェクトはデフォルトでオールド世代に直接割り当てられますが、一時的な存在の巨大なオブジェクトの場合、ガベージコレクタに負の影響を与える可能性があります。この問題を解決するために、G1 は Humongous 領域を割り当てるために使用されます。H 領域にオブジェクトを割り当てることができない場合、G1 は連続した H 領域を検索して割り当てます。連続した H 領域を見つけるために、フル GC を実行する必要がある場合があります。 - オブジェクトの割り当てポリシー
- TLAB(スレッドローカル割り当てバッファ):スレッドローカル割り当てバッファ(TLAB)は、オブジェクトをできるだけ迅速に割り当てるためのものです。共有スペースでオブジェクトを割り当てる場合、空きスペースポインタを管理するためにいくつかの同期メカニズムが必要です。Eden 領域では、各スレッドにはオブジェクトを割り当てるための固定の領域、つまり TLAB があります。オブジェクトを割り当てるとき、スレッド間で同期する必要はありません。
- Eden 領域での割り当て:TLAB スペースで割り当てることができないオブジェクトは、Eden 領域で割り当てることを JVM が試みます。Eden 領域にオブジェクトを割り当てるスペースがない場合、オールド世代でスペースを割り当てる必要があります。
- Humongous 領域での割り当て
-
ヤング GC プロセス
- 初期マーク:stw、gc ルートとヤング領域から直接参照されるオブジェクト(つまり、gc ルート自体)をマークします。
- RSet の処理と更新:RSet の情報を処理し、オールド世代のオブジェクトがヤング世代のオブジェクトを保持する関連参照を追加します。
- クリーニングフェーズ:stw、すべてのヤングリージョンを CSet にパックします。予測される回収時間が指定された許容時間よりも短い場合、G1 は Eden 領域のリージョン数を増やしてクリーニングを行いません。予測される回収時間が指定された許容時間よりも長い場合、G1 はマークコピー操作を実行し、すべての生存オブジェクトを空の Survivor 領域にコピーします。
-
ミックス GC プロセス
-
初期マーク:これはヤング GC の一環であり、一時停止が発生します。
-
ルート領域スキャン
-
並行マークフェーズ:参照の変更が発生した場合(新しいメモリをオブジェクトに割り当てることは含まれません)、書き込みバリアはこれらの参照の元の値をキャプチャし、ログバッファに記録します。そして後で処理します。新しく作成されたオブジェクトの処理には、G1 が異なる方法を使用しています。G1 は 2 つの TAMS 変数を使用して新しく作成されたオブジェクトを判断します。1 つは previous TAMS、もう 1 つは next TAMS です。2 つの TAMS の間にあるオブジェクトは新しく割り当てられたオブジェクトです。
-
再マーク:stw、SATB ライトバリアのオブジェクト参照を処理し、グレーにマークされたオブジェクトを再度マークします。
-
クリーニングフェーズ