ホームページ  >  記事  >  Java  >  Javaの知識まとめとJVMの詳細説明

Javaの知識まとめとJVMの詳細説明

WBOY
WBOY転載
2022-07-12 17:20:031917ブラウズ

この記事では、java に関する関連知識を提供します。主に、JVM のメモリ領域分割、JVM クラスのロード機構、VM ガベージ コレクションなど、JVM 関連の問題を整理しています。内容を見てみましょう。皆様のお役に立てれば幸いです。

Javaの知識まとめとJVMの詳細説明

推奨学習: 「java ビデオ チュートリアル

1. JVM のメモリ領域分割

JVM はなぜ行うのかこれらの領域をどのように分割するか? JVM メモリはオペレーティング システムから適用され、JVM は機能要件に応じてこれらを小さなモジュールに分割します。このようにして、大きなサイトを小さなモジュールに分割することができ、各モジュールは独自の機能を担当します。それでは、これらの領域の機能を見てみましょう!

1. プログラム カウンタ

プログラム カウンタは、メモリ領域内で最も小さいものです。次に実行する命令のアドレスが保存されます (命令はバイトコードです。一般的なプログラムを実行するには、JVM がバイトコードをメモリにロードする必要があります。その後、プログラムはメモリから命令を 1 つずつ取り出します) CPU は 1 つのプロセスにサービスを提供するだけでなく、すべてのプロセスにサービスを提供し、同時にプログラムを実行するため、CPU はどの命令が現在実行されているか、次の命令がどこにあるかを記憶する必要があります。オペレーティング システムはスレッド単位で実行をスケジュールするため、各スレッドには独自の実行場所が必要です。つまり、各スレッドにプログラムが必要です。位置を記録するカウンター!)2.スタック

スタックには主に

ローカル変数とメソッド呼び出し情報

が保存されます。新しいメソッドの呼び出しが含まれる限り、「プッシュ」操作が行われます。メソッドが実行されるたびに、は「プッシュ」操作となり、各スレッドはスタックのコピーを持ちます。
したがって、再帰の場合は、再帰条件を制御する必要があり、そうでない場合はスタック オーバーフロー (StackOverflowException) ) 例外が発生する可能性があります!Javaの知識まとめとJVMの詳細説明
3. ヒープ

ヒープはメモリ内の最大の領域であり、ヒープはメモリ内の最大の領域です。各プロセスにはスペースが必要です。コピーは 1 つだけです。プロセス内の複数のスレッドはヒープを共有し、主に新しいオブジェクトとオブジェクトのメンバー変数を格納します。たとえば、 s がメソッド内にある場合は String s = new String() となります。つまり、ローカル変数はスタック上にあります。 s がメンバー変数の場合、それはヒープ上にあります。 New String() はオブジェクトのオントロジーであり、オブジェクトはヒープ上にあります。ここが混乱しやすい点です。また、ヒープも重要なポイントの 1 つはガベージ コレクションに関するものであり、これについては後ほど詳しく紹介します!

4. メソッド領域メソッド領域

には「クラス オブジェクト」が格納されます。

, 通常作成する .java コードは、コンパイラによって変換された後、.class (バイナリ バイトコード) になります。その後、.class はメモリにロードされ、JVM によってクラス オブジェクトに構築されます (ロード プロセスは「」と呼ばれます)。クラスの読み込み」)、これらのクラス オブジェクトはメソッド領域に格納されます。メソッド領域には、クラスがどのようなものであるか (クラスの名前、クラスのメンバーとそのメンバー名、メンバーの型、クラスのメソッド) が具体的に記述されます。クラスオブジェクトには、そのメソッド名、メソッドの種類、命令などが格納されていますが、それが静的メンバです。一般に、静的に変更されたメンバはクラスの属性となり、通常のメソッドはインスタンスの属性と呼ばれます。これは大きな違いです)!

上記の紹介はJVMにおける共通領域であり、一部のJVMのメモリ領域分割は必ずしも実態と一致しているわけではありません。 JVM実装の領域 部門が異なります JVMのバージョンやメーカーによって違いがあるかもしれませんが、私たち一般プログラマにとっては、JVMを実装しない限り、それを理解する必要はありません上記について話しましょう。いくつかの共通領域を理解するだけです!

2. JVM クラス ロード メカニズム

クラス ロードは、実際には、JVM を設計する上で重要な中心機能です。実行環境関数、非常に重いので簡単に紹介します!

上記はクラスロードの具体的な処理です、最後のUsingとUnloadingは使用するための処理であり、実際には使用されません。最初の 3 つの大きなステップを紹介します:

1.Loading(Loading)

読み込みフェーズでは、 はまず対応する .class ファイルを見つけ、次に .class ファイルを開いて (バイト ストリームに従って) 読み取ります。 Class オブジェクトを生成します 、これは完了したクラス ロード (クラス ロード) とは異なりますので、混同しないでください!
クラス ファイルの特定の形式 (Java コンパイラを実装したい場合は、次のように構築する必要があります)この形式で JVM を実装するには、この形式に従ってロードする必要があります!):
Javaの知識まとめとJVMの詳細説明
この形式を観察すると、.class ファイルがすべてのコア情報を表現していることがわかります。 .java ファイルですが、整理されています。形式が変更されているため、読み込みリンクは最初に、読み取られた情報をクラス オブジェクトに埋め込みます。

2. リンク

リンクは、通常、複数のファイルを確立することです。

2.1.Verification(検証)

検証は、主に読み取られたコンテンツが仕様で指定された形式と正確に一致するかどうかを検証するための検証プロセスです読み込んだデータ形式が仕様に準拠していないことが判明した場合、クラスのロードは失敗し、例外がスローされます!

2.2.Preparation(準備)

準備フェーズisofficial 定義した変数(static変数、staticで変更した変数)のメモリ確保とクラス変数の初期値の設定の段階で、static変数ごとにメモリを確保して値を設定します。 0!

2.3.解決 (分析)

解決ステージは、Java 仮想マシン が定数プール内のシンボル参照を直接参照に置き換えるプロセスです , これは定数を初期化するプロセスでもあります。.class ファイル内の定数は中央に配置され、各定数には番号が付けられます。.class ファイル内の構造の初期状態は単なるレコード番号です。この番号に基づいて対応するコンテンツを見つけて、クラス オブジェクトに埋め込むことができます!

3.初期化(Initialization)

初期化ステージは クラス オブジェクトの実際の初期化です。 (書かれたコードによると)、特に静的メンバーの場合

4. 典型的な面接の質問

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();
    }}

出力結果を自分で書いてみることもできます

# #このような質問を行うには、いくつかの主要な原則を理解する必要があります:

  • 静的コード ブロックはクラスの読み込みフェーズ中に実行されます。インスタンスを作成したい場合は、まず次のことを行う必要があります。クラスの読み込みを実行します。

  • 静的コード ブロックは、クラスの読み込みフェーズ中に 1 回だけ実行されます。他のステージは再度実行されません。

  • 構築メソッドと構築コード ブロックはインスタンス化されるたびに実行され、構築コード ブロックは構築メソッドの前に実行されます~~

  • 親クラスが最初に実行され、そしてサブクラスは最後に実行されます!

  • プログラムはメイン、メインの Test メソッドから実行されるため、メインを実行するには最初に Test クラスをロードする必要があります

  • このクラスが関与している場合のみ、クラス内のものがロードされます

输出结果:
A的静态代码块
B的静态代码块
A的构造代码块
A的构造方法
B的构造代码块
B的构造方法
A的构造代码块
A的构造方法
B的构造代码块
B的构造方法
5. 親委任モデル

これはクラスロードのリンクですロード段階 (前半部分) にあります。親委任モデル

は、JVM のクラス ローダーを記述します。クラスの完全修飾名 (java.lang.String) の使用方法。 .class ファイル。ここでのクラス ローダーは、JVM によって特別に提供されるオブジェクトです。クラス ローダーは主にクラスのロードを担当するため、ファイルを見つけるプロセスもクラス ローダーの役割を果たします。.class ファイルが配置される場所は数多くありますが、それらは JDK ディレクトリに配置する必要があり、一部はプロジェクト ディレクトリに配置され、一部は他の特定の場所に配置されるため、JVM は複数のクラス ローダーを提供し、各クラス ローダーはスライスを担当し、主に 3 つのデフォルト クラスがあります。ローダー:

  • BootStrapClassLoader: 標準ライブラリ内のクラスのロードを担当します (String、ArrayList、Random、Scanner...)

  • ExtensionClassLoader: JDK 拡張クラスのロードを担当します (現在はほとんど使用されていません)

  • ApplicationClassLoader: 現在のプロジェクト ディレクトリ内のクラスのロードを担当します

  • さらに、プログラマクラスのロードをカスタマイズすることもできます 他のディレクトリにクラスをロードするために、Tomcat はクラス ローダーをカスタマイズして、特に Web アプリの .classes をロードします

親委任モデルでこれについて説明します

検索のプロセスディレクトリは、上記のクラス ローダーが連携する方法です。 java.lang.String:

  • プログラムを開始すると、最初に ApplicationClassLoader クラス ローダーに入ります。

  • #ApplicationClassLoader クラス ローダーは、その親ローダーがロードされているかどうかを確認します。ロードされていない場合は、親クラス ローダー ExtensionClassLoader を呼び出します
  • ExtensionClassLoader クラス ローダー親ローダーがロードされているかどうかを確認します。そうでない場合は、親クラス ローダーを呼び出します。BootStrapClassLoader
  • BootStrapClassLoader クラス ローダーは、親ローダーがロードされているかどうかもチェックし、それを検出します。親がないため、担当するディレクトリをスキャンします
  • #これで、java.lang.String クラスが標準ライブラリに見つかり、BootStrapClassLoader ローダーが後続のロード プロセスを担当し、検索プロセスは終了です。


    Javaの知識まとめとJVMの詳細説明

自分が作成した Test クラスを探すことを検討してください。

  • プログラムが開始されると、最初に ApplicationClassLoader クラス ローダーに入ります。

  • ApplicationClassLoader クラス ローダーは、親ローダーがロードされているかどうかを確認します。ロードされていない場合は、親クラス ローダーを呼び出します。 ExtensionClassLoader
  • ExtensionClassLoader クラス ローダーは、親クラス ローダーがロードされているかどうかを確認します。親ローダーがロードされています。そうでない場合は、親クラス ローダーを呼び出します。BootStrapClassLoader
  • BootStrapClassLoader クラス ローダーもそれをチェックします。親ローダーがロードされているかどうか、そして、そこにあることが判明しましたは親ではないため、担当するディレクトリをスキャンします。スキャンされない場合は、子ローダーに戻ってスキャンを続行します。
  • #ExtensionClassLoader 担当するディレクトリをスキャンします。が、スキャンされません。その後、サブローダーに戻ってスキャンを続行します。
  • ApplicationClassLoader は、担当するディレクトリもスキャンします。作成したクラスは独自のディレクトリにあります。プロジェクトディレクトリをダウンロードして見つけられるようにすると、その後のクラスロードはApplicationClassLoadで完了します この時点でディレクトリ検索のリンクは終わりました~~ (なお、ApplicationClassLoaderが見つからない場合はClassNotFoundExceptionをスローします)例外)

  • Javaの知識まとめとJVMの詳細説明

    この検索ルールのセットは、親委任モデルと呼ばれます。では、なぜ JVM はこのように設計されているのでしょうか?その理由は、
  • プログラマが作成したクラスは、同じ完全修飾クラス名を持ちます。これで、自分で作成したクラスの代わりに、標準ライブラリ
内のクラスを正常にロードすることもできます!!!

さらに、カスタム クラス ローダーの場合は、 , この親委任モデルに準拠する必要がありますか? 回答 準拠できるかどうかは、主に要件によって異なります。たとえば、Tomcat が Web アプリにクラスをロードする場合、準拠されません。なぜなら、上記に準拠するとクラスローダーを見つけることが不可能だからです!
3. JVM ガベージ コレクション

JVM のガベージ コレクション メカニズム (GC)

通常、コードの作成には、変数の作成、オブジェクトの新規作成、メソッドの呼び出しなど、メモリの適用が含まれることがよくあります。クラスの読み込み... メモリを適用するタイミングは一般に明確です (必要に応じてメモリを適用する必要があります)。特定のデータを保存します)が、メモリを解放するタイミングがあまり明確ではなく、あまりにも早く解放すると機能しません(まだ使用する必要がある場合は、結果が解放されているため、使用可能なメモリがありません)データには「行き場がない」)、リリースが遅い場合は機能しません(リリースが遅いと、大量の蓄積により使用可能なメモリが徐々に少なくなる可能性が高くなります)メモリ リークの問題がある (つまり、使用できるメモリがない) ため、

メモリの解放は適切でなければなりません #! さらに、ガベージ コレクションのジョブはランタイム環境 A によって実行されます。ガベージコレクションにはメモリ解放操作が完了するまでに多くの作業が必要となるため、プログラマーの精神的負担は大幅に軽減されますが、ガベージコレクションには、①追加のオーバーヘッドが発生する(より多くのリソースが消費される)、②ソフトウェアのスムーズな動作に影響を与える可能性がある、というデメリットもあります。プログラム (ガベージ コレクションは STW 問題 (Stop The World) を引き起こすことがよくあります)ガベージ コレクションとはどのような種類のメモリですか? すべてリサイクルする必要がありますか?
もちろん違います。上記の 4 つの領域について説明します。

プログラム カウンター: このメモリは固定サイズであり、解放を伴わないため、GC は必要ありません。

スタック: 関数呼び出し時;# が完了すると、対応するスタック フレームが自動的に解放され、GC は必要ありません;

ヒープ: 最も GC を必要とするメモリです。一般的なコードでは大量のメモリがヒープ上にあります。;
  • これら 3 つの領域のどれを解放する必要がありますか? 部分的に使用され、部分的に使用されなくなった
  • オブジェクトの場合、全体の
  • は解放されません。使用されなくなった場合は、本当にリリースされているため、GC でオブジェクトが半分になる状況は発生しません。したがって、
  • ガベージ コレクションの基本単位は、バイトではなくオブジェクトです。
    Javaの知識まとめとJVMの詳細説明メソッド領域です。 : クラス オブジェクト、クラスのロード、クラスがアンロードされるときのみメモリを解放する必要があり、アンロード操作は非常に低頻度であるため、GC はほとんど関与しません!
    リサイクル方法を詳しく見てみましょう:
  • 1. ゴミの発見/ゴミの特定
  • 現在、主流のソリューションは 2 つあります:
1.1. 参照カウントに基づく

これは Java で採用されている解決策ではなく、Python やその他の言語の解決策です。そのため、ここではあまり深入りせずに簡単に紹介します~

そして、参照カウントについての具体的な考え方は次のとおりです。オブジェクトごとに、このオブジェクトがそれを指す参照の数を保存するために追加の小さなメモリが導入されます。

そして、このような参照数には 2 つの欠陥があります。

  • スペース使用率は比較的低い!!!。オブジェクト自体が比較的大きい場合 (数百ワード)、新しいオブジェクトごとにカウンターを装備する必要があります。カウンターは 4 バイトであると想定されます。セクション) の場合、このカウンタは問題になりません。オブジェクト自体が比較的小さい (4 バイト) と、さらに 4 バイトがスペース使用率を 2 倍にすることに相当するため、スペース使用率は比較的低くなります ~
  • 循環参照の問題がある
    Javaの知識まとめとJVMの詳細説明
    したがって、参照カウントを使用すると多くの問題が発生します。Python、PHP などを考慮してください。参照カウンタを使用して GC を完了しますが、他のメカニズムと連携して GC を完了します!

1.2. 到達可能性分析に基づく

到達可能性分析は Java で採用されているソリューションです。 いくつかの追加スレッドを介して、メモリ空間全体 内のオブジェクトをいくつかの開始位置 (GCRoots) で定期的にスキャンします。その後、深さ優先トラバーサル (ツリーとして想像できます) に似ており、すべてをマークします。アクセス可能なオブジェクト (マークされたオブジェクトは到達可能なオブジェクト)、マークされていないオブジェクトは到達不可能なオブジェクト、つまりガベージであり、解放される必要があります!
ここの GCRoots (これらの場所からトラバースを開始します):

  • スタック上のローカル変数;
  • 定数プール内の参照によってポイントされるオブジェクト;
  • メソッド領域内の静的メンバーによってポイントされるオブジェクト;
#到達可能性分析の利点は、

参照カウントの欠点であるスペース使用率の低さと循環参照を解決できることです;到達可能性分析の欠点も明らかです: システムのオーバーヘッドが大きく、 #~したがって、ガベージを見つけることも非常に簡単です。中心となるのは、このオブジェクトが将来使用されるかどうかを確認することです。まだ使用されます。存在するかどうかを確認してください。

2. ガベージを解放する

ガベージとは何かを明確にしたので、次のステップはガベージをリサイクルすることです。基本的な戦略は 3 つあります。

2.1. マーク - 削除してください

Javaの知識まとめとJVMの詳細説明ここの

マークは到達可能性を示します。クリアとはメモリを解放することです

. 上記をメモリとし、チェックを入れた部分がゴミを表します. このとき直接解放すると、メモリはシステムに戻りますが、解放されたメモリは離散的になります. が連続しておらず、これによって引き起こされる問題は「メモリの断片化」です。空きメモリがたくさんある可能性があります。合計が 1G であると仮定します。現時点で 500MB の容量を申請したい場合は、申請できます。ただし、ここでアプリケーションが失敗する可能性があります(申請する500MBは連続メモリであり、毎回申請されるメモリは連続メモリ空間であり、ここでの1Gは複数のフラグメントの合計である可能性があるため)。この問題は実際にはプログラムの実行に大きな影響を及ぼします2.2. コピー アルゴリズム

上記のマーククリア戦略はメモリの断片化の問題を引き起こす可能性があるため、

解決するためのコピー アルゴリズムを導入しましたこの問題 質問


上記はメモリの一部です。コピー アルゴリズムの戦略は、メモリの半分を使用し、半分を捨て、すべてを使用しないことです。通常の使用では、ジャンクではない部分を残りの半分にコピーします (このコピーは JVM によって内部で処理されます。心配する必要はありません)。その後、以前に使用されていたすべてのメモリが解放されるため、メモリの断片化の問題は簡単に解決されます。 !Javaの知識まとめとJVMの詳細説明したがって、コピー アルゴリズムには 2 つの大きな問題があります。

メモリ領域の使用率が低い (一般メモリのみが使用される);
  • 保持するオブジェクトが多数ある場合
  • 2.3. マーク付けと並べ替え

#これは、コピー アルゴリズムの

さらなる改善です

!
マークとソートの戦略は、Javaの知識まとめとJVMの詳細説明ゴミではないメモリを集めて、後続のメモリをすべて解放する
です。これは、中間要素を削除する操作と同様です。シーケンス テーブルには移動プロセスがあります! このソリューションではスペース使用率が高くなりますが、要素のコピー/移動によるオーバーヘッドが高いという問題を解決する方法はまだありません!
上記の 3 つはありますが、ソリューションは問題を解決できますが、それぞれに独自の欠点があるため、実際には、JVM での実装は問題を解決します。複数のソリューションの組み合わせは「世代リサイクル」と呼ばれます!!!

2.4 世代リサイクル

ここでの世代とは、(オブジェクトの「年齢」に従って) オブジェクトを分類することです。分類します。ここでの年齢とは、オブジェクトが GC スキャンのラウンドを生き延びていることを意味します。これは「1 年古い」と呼ばれます)。さまざまな年代のオブジェクト、さまざまな計画が採用されています!!!


これが世代を超えたリサイクル プロセス全体です!Javaの知識まとめとJVMの詳細説明

3. ガベージ コレクター

上記のガベージの検索とガベージの解放は単なるアルゴリズム上のアイデアであり、実際の実装プロセスではありません。上記のアルゴリズム モジュールの実際の実装は「ガベージ コレクター」です。特定のガベージ コレクター:

3.1. シリアル コレクターとシリアル オールド コレクター

シリアル コレクターは新しい世代に提供されるガベージ コレクターであり、シリアル オールド コレクターは新しい世代に提供されるガベージ コレクターです。古い世代。これら 2 つのコレクターは連続して収集し、スキャンしてガベージを解放するときにビジネス スレッドの動作を停止する必要があるため、このようにスキャンがいっぱいになり、解放が遅くなります。また、深刻な STW が生成される可能性もあります!

3.2.ParNew コレクター、Parallel Scavenge コレクター、および Parallel Old コレクター

ParNew コレクター、Parallel Scavenge コレクターはすべて新しい世代に提供されます。Parallel Scavenge コレクターは、ParNew コレクターと比較していくつかのパラメーターを追加し、 STW 時ですが、より強力な機能がいくつかあります。古い世代には Parallel Old コレクタが提供されています。これら 3 つのコレクタはすべて並列コレクションです。はい、ガベージのスキャンとガベージの解放の機能を解決するためのマルチスレッド アプローチが導入されています!

上記のコレクタは、古いガベージ コレクション手法である歴史から残されたものです。さらに、2 つの更新されたガベージ コレクタを紹介します!

3.3.CMS コレクタ

CMS コレクタは、より詳細に設計されています。本来の目的は STW 時間をできる限り短縮することです, Java8 は CMS コレクターを使用します. ここでは CMS コレクターのプロセスについて簡単に紹介します:

    イニシャル マーク: 非常に高速で、短い STW が発生します (GCRoots を見つけるだけです);
  1. 同時マーキング: 非常に高速ですが、ビジネス スレッドと同時に実行でき、STW は生成されません;
  2. 注: 2 つのビジネス コードは、同時マーキングの結果に影響を与える可能性があります (ビジネス スレッドが実行されており、新しいガベージが生成される可能性があります)。そのため、このステップは 2 の結果を微調整することです。STW が発生しますが、微調整のみで、速度は非常に高速です。
  3. 上記の 3 つの手順はすべて到達可能性分析に基づいています!
  4. メモリのリサイクル: ビジネス スレッドと同時に実行されるため、STW は生成されませんこれはマーキングとソートに基づいています;
3.4.G1 コレクター

G1 コレクターは

唯一のフルリージョン ガベージ コレクターです。G1 コレクターには次の特徴があります。 Java11 から使用されています。このコレクターは、メモリ全体を多くの小さな領域に分割し、これらの領域に異なるマークを付けます。一部の領域には新しい世代のオブジェクトが格納され、一部の領域には古い世代のオブジェクトが格納されます。その後、スキャン時に複数の領域が一度にスキャンされます ( GC の 1 ラウンドでスキャンを完了する必要はなく、複数回スキャンする必要があります)。これはビジネス コードに影響を与えます。また、これが最小です。

の中心となるアイデアこれら 2 つの新しいコレクターは、それらを部分に分割することです。G1 は現在、STW の一時停止時間を 1ms 未満にするように最適化できますが、これは完全に許容されます! 上記は JVM に関するものです。いくつかの検討を行った後、ここでのコレクターに関する主な点は次のとおりです。これを理解するには、主に上記のガベージ コレクションのアイデアが非常に重要であるためです。!!!

推奨される学習: 「

Java ビデオ チュートリアル

以上がJavaの知識まとめとJVMの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。