この記事では、java に関する関連知識を提供します。主に、JVM のメモリ領域分割、JVM クラスのロード機構、VM ガベージ コレクションなど、JVM 関連の問題を整理しています。内容を見てみましょう。皆様のお役に立てれば幸いです。
推奨学習: 「java ビデオ チュートリアル 」
JVM はなぜ行うのかこれらの領域をどのように分割するか? JVM メモリはオペレーティング システムから適用され、JVM は機能要件に応じてこれらを小さなモジュールに分割します。このようにして、大きなサイトを小さなモジュールに分割することができ、各モジュールは独自の機能を担当します。それでは、これらの領域の機能を見てみましょう!
プログラム カウンタは、メモリ領域内で最も小さいものです。次に実行する命令のアドレスが保存されます (命令はバイトコードです。一般的なプログラムを実行するには、JVM がバイトコードをメモリにロードする必要があります。その後、プログラムはメモリから命令を 1 つずつ取り出します) CPU は 1 つのプロセスにサービスを提供するだけでなく、すべてのプロセスにサービスを提供し、同時にプログラムを実行するため、CPU はどの命令が現在実行されているか、次の命令がどこにあるかを記憶する必要があります。オペレーティング システムはスレッド単位で実行をスケジュールするため、各スレッドには独自の実行場所が必要です。つまり、各スレッドにプログラムが必要です。位置を記録するカウンター!)2.スタック
が保存されます。新しいメソッドの呼び出しが含まれる限り、「プッシュ」操作が行われます。メソッドが実行されるたびに、は「プッシュ」操作となり、各スレッドはスタックのコピーを持ちます。
したがって、再帰の場合は、再帰条件を制御する必要があり、そうでない場合はスタック オーバーフロー (StackOverflowException) ) 例外が発生する可能性があります!
3. ヒープ
4. メソッド領域メソッド領域
には「クラス オブジェクト」が格納されます。上記の紹介はJVMにおける共通領域であり、一部のJVMのメモリ領域分割は必ずしも実態と一致しているわけではありません。 JVM実装の領域 部門が異なります JVMのバージョンやメーカーによって違いがあるかもしれませんが、私たち一般プログラマにとっては、JVMを実装しない限り、それを理解する必要はありません上記について話しましょう。いくつかの共通領域を理解するだけです!
クラス ロードは、実際には、JVM を設計する上で重要な中心機能です。実行環境関数、非常に重いので簡単に紹介します!2. JVM クラス ロード メカニズム
読み込みフェーズでは、 はまず対応する .class ファイルを見つけ、次に .class ファイルを開いて (バイト ストリームに従って) 読み取ります。 Class オブジェクトを生成します 、これは完了したクラス ロード (クラス ロード) とは異なりますので、混同しないでください!
クラス ファイルの特定の形式 (Java コンパイラを実装したい場合は、次のように構築する必要があります)この形式で JVM を実装するには、この形式に従ってロードする必要があります!):
この形式を観察すると、.class ファイルがすべてのコア情報を表現していることがわかります。 .java ファイルですが、整理されています。形式が変更されているため、読み込みリンクは最初に、読み取られた情報をクラス オブジェクトに埋め込みます。
リンクは、通常、複数のファイルを確立することです。
検証は、主に読み取られたコンテンツが仕様で指定された形式と正確に一致するかどうかを検証するための検証プロセスです読み込んだデータ形式が仕様に準拠していないことが判明した場合、クラスのロードは失敗し、例外がスローされます!
準備フェーズisofficial 定義した変数(static変数、staticで変更した変数)のメモリ確保とクラス変数の初期値の設定の段階で、static変数ごとにメモリを確保して値を設定します。 0!
解決ステージは、Java 仮想マシン が定数プール内のシンボル参照を直接参照に置き換えるプロセスです , これは定数を初期化するプロセスでもあります。.class ファイル内の定数は中央に配置され、各定数には番号が付けられます。.class ファイル内の構造の初期状態は単なるレコード番号です。この番号に基づいて対応するコンテンツを見つけて、クラス オブジェクトに埋め込むことができます!
初期化ステージは クラス オブジェクトの実際の初期化です。 (書かれたコードによると)、特に静的メンバーの場合
class A { public A(){ System.out.println("A的构造方法"); } { System.out.println("A的构造代码块"); } static { System.out.println("A的静态代码块"); }}class B extends A{ public B(){ System.out.println("B的构造方法"); } { System.out.println("B的构造代码块"); } static { System.out.println("B的静态代码块"); }}public class Test extends B{ public static void main(String[] args) { new Test(); new Test(); }}
出力結果を自分で書いてみることもできます
输出结果: A的静态代码块 B的静态代码块 A的构造代码块 A的构造方法 B的构造代码块 B的构造方法 A的构造代码块 A的构造方法 B的构造代码块 B的构造方法5. 親委任モデル これはクラスロードのリンクですロード段階 (前半部分) にあります。親委任モデル
は、JVM のクラス ローダーを記述します。クラスの完全修飾名 (java.lang.String) の使用方法。 .class ファイル。ここでのクラス ローダーは、JVM によって特別に提供されるオブジェクトです。クラス ローダーは主にクラスのロードを担当するため、ファイルを見つけるプロセスもクラス ローダーの役割を果たします。.class ファイルが配置される場所は数多くありますが、それらは JDK ディレクトリに配置する必要があり、一部はプロジェクト ディレクトリに配置され、一部は他の特定の場所に配置されるため、JVM は複数のクラス ローダーを提供し、各クラス ローダーはスライスを担当し、主に 3 つのデフォルト クラスがあります。ローダー:
検索のプロセスディレクトリは、上記のクラス ローダーが連携する方法です。 java.lang.String:
さらに、カスタム クラス ローダーの場合は、 , この親委任モデルに準拠する必要がありますか? 回答 準拠できるかどうかは、主に要件によって異なります。たとえば、Tomcat が Web アプリにクラスをロードする場合、準拠されません。なぜなら、上記に準拠するとクラスローダーを見つけることが不可能だからです!
3. JVM ガベージ コレクション
メモリの解放は適切でなければなりません #! さらに、ガベージ コレクションのジョブはランタイム環境 A によって実行されます。ガベージコレクションにはメモリ解放操作が完了するまでに多くの作業が必要となるため、プログラマーの精神的負担は大幅に軽減されますが、ガベージコレクションには、①追加のオーバーヘッドが発生する(より多くのリソースが消費される)、②ソフトウェアのスムーズな動作に影響を与える可能性がある、というデメリットもあります。プログラム (ガベージ コレクションは STW 問題 (Stop The World) を引き起こすことがよくあります)ガベージ コレクションとはどのような種類のメモリですか? すべてリサイクルする必要がありますか?
もちろん違います。上記の 4 つの領域について説明します。
1.1. 参照カウントに基づくこれは Java で採用されている解決策ではなく、Python やその他の言語の解決策です。そのため、ここではあまり深入りせずに簡単に紹介します~スタック: 関数呼び出し時;# が完了すると、対応するスタック フレームが自動的に解放され、GC は必要ありません;
ヒープ: 最も GC を必要とするメモリです。一般的なコードでは大量のメモリがヒープ上にあります。;
- これら 3 つの領域のどれを解放する必要がありますか? 部分的に使用され、部分的に使用されなくなった
- オブジェクトの場合、全体の
は解放されません。使用されなくなった場合は、本当にリリースされているため、GC でオブジェクトが半分になる状況は発生しません。したがって、- ガベージ コレクションの基本単位は、バイトではなくオブジェクトです。
1. ゴミの発見/ゴミの特定
メソッド領域です。 : クラス オブジェクト、クラスのロード、クラスがアンロードされるときのみメモリを解放する必要があり、アンロード操作は非常に低頻度であるため、GC はほとんど関与しません!
リサイクル方法を詳しく見てみましょう:- 現在、主流のソリューションは 2 つあります:
到達可能性分析は Java で採用されているソリューションです。 いくつかの追加スレッドを介して、メモリ空間全体 内のオブジェクトをいくつかの開始位置 (GCRoots) で定期的にスキャンします。その後、深さ優先トラバーサル (ツリーとして想像できます) に似ており、すべてをマークします。アクセス可能なオブジェクト (マークされたオブジェクトは到達可能なオブジェクト)、マークされていないオブジェクトは到達不可能なオブジェクト、つまりガベージであり、解放される必要があります!
ここの GCRoots (これらの場所からトラバースを開始します):
参照カウントの欠点であるスペース使用率の低さと循環参照を解決できることです;到達可能性分析の欠点も明らかです: システムのオーバーヘッドが大きく、 #~したがって、ガベージを見つけることも非常に簡単です。中心となるのは、このオブジェクトが将来使用されるかどうかを確認することです。まだ使用されます。存在するかどうかを確認してください。
2. ガベージを解放する
2.1. マーク - 削除してください
ここの
マークは到達可能性を示します。クリアとはメモリを解放することです. 上記をメモリとし、チェックを入れた部分がゴミを表します. このとき直接解放すると、メモリはシステムに戻りますが、解放されたメモリは離散的になります. が連続しておらず、これによって引き起こされる問題は「メモリの断片化」です。空きメモリがたくさんある可能性があります。合計が 1G であると仮定します。現時点で 500MB の容量を申請したい場合は、申請できます。ただし、ここでアプリケーションが失敗する可能性があります(申請する500MBは連続メモリであり、毎回申請されるメモリは連続メモリ空間であり、ここでの1Gは複数のフラグメントの合計である可能性があるため)。この問題は実際にはプログラムの実行に大きな影響を及ぼします2.2. コピー アルゴリズム
上記はメモリの一部です。コピー アルゴリズムの戦略は、メモリの半分を使用し、半分を捨て、すべてを使用しないことです。通常の使用では、ジャンクではない部分を残りの半分にコピーします (このコピーは JVM によって内部で処理されます。心配する必要はありません)。その後、以前に使用されていたすべてのメモリが解放されるため、メモリの断片化の問題は簡単に解決されます。 !したがって、コピー アルゴリズムには 2 つの大きな問題があります。
!
マークとソートの戦略は、ゴミではないメモリを集めて、後続のメモリをすべて解放する
です。これは、中間要素を削除する操作と同様です。シーケンス テーブルには移動プロセスがあります! このソリューションではスペース使用率が高くなりますが、要素のコピー/移動によるオーバーヘッドが高いという問題を解決する方法はまだありません!
上記の 3 つはありますが、ソリューションは問題を解決できますが、それぞれに独自の欠点があるため、実際には、JVM での実装は問題を解決します。複数のソリューションの組み合わせは「世代リサイクル」と呼ばれます!!!
2.4 世代リサイクル
これが世代を超えたリサイクル プロセス全体です!
上記のガベージの検索とガベージの解放は単なるアルゴリズム上のアイデアであり、実際の実装プロセスではありません。上記のアルゴリズム モジュールの実際の実装は「ガベージ コレクター」です。特定のガベージ コレクター:
シリアル コレクターは新しい世代に提供されるガベージ コレクターであり、シリアル オールド コレクターは新しい世代に提供されるガベージ コレクターです。古い世代。これら 2 つのコレクターは連続して収集し、スキャンしてガベージを解放するときにビジネス スレッドの動作を停止する必要があるため、このようにスキャンがいっぱいになり、解放が遅くなります。また、深刻な STW が生成される可能性もあります!
ParNew コレクター、Parallel Scavenge コレクターはすべて新しい世代に提供されます。Parallel Scavenge コレクターは、ParNew コレクターと比較していくつかのパラメーターを追加し、 STW 時ですが、より強力な機能がいくつかあります。古い世代には Parallel Old コレクタが提供されています。これら 3 つのコレクタはすべて並列コレクションです。はい、ガベージのスキャンとガベージの解放の機能を解決するためのマルチスレッド アプローチが導入されています!
上記のコレクタは、古いガベージ コレクション手法である歴史から残されたものです。さらに、2 つの更新されたガベージ コレクタを紹介します!
CMS コレクタは、より詳細に設計されています。本来の目的は STW 時間をできる限り短縮することです, Java8 は CMS コレクターを使用します. ここでは CMS コレクターのプロセスについて簡単に紹介します:
唯一のフルリージョン ガベージ コレクターです。G1 コレクターには次の特徴があります。 Java11 から使用されています。このコレクターは、メモリ全体を多くの小さな領域に分割し、これらの領域に異なるマークを付けます。一部の領域には新しい世代のオブジェクトが格納され、一部の領域には古い世代のオブジェクトが格納されます。その後、スキャン時に複数の領域が一度にスキャンされます ( GC の 1 ラウンドでスキャンを完了する必要はなく、複数回スキャンする必要があります)。これはビジネス コードに影響を与えます。また、これが最小です。
の中心となるアイデアこれら 2 つの新しいコレクターは、それらを部分に分割することです。G1 は現在、STW の一時停止時間を 1ms 未満にするように最適化できますが、これは完全に許容されます! 上記は JVM に関するものです。いくつかの検討を行った後、ここでのコレクターに関する主な点は次のとおりです。これを理解するには、主に上記のガベージ コレクションのアイデアが非常に重要であるためです。!!!推奨される学習: 「Java ビデオ チュートリアル 」
以上がJavaの知識まとめとJVMの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。