クラスの読み込みメカニズムとライフサイクルの詳細な説明

クラスローディングメカニズム

Java仮想マシンは、クラスを記述するデータをClassファイルからメモリにロードし、データを検証、変換、分析、および初期化し、最終的に仮想マシンで直接使用できるJavaタイプを形成します。このプロセスは、仮想マシンのクラスロードメカニズムと呼ばれます。 。

クラスのライフサイクル

クラスは、仮想マシンのメモリへのロードからメモリからのアンロードに始まります。そのライフサイクル全体には、ロード、検証、準備、分析、初期化、使用、およびアンロードが含まれますこれらの7つのステージには、検証、準備、分析が含まれます。これらのパーツをまとめて接続と呼びます。

image-20200827153624097

ロード、検証、準備、初期化、およびアンロードの5つの段階の順序が決定されます。このタイプのロードプロセスは、この順序で段階的に開始する必要がありますが、解析フェーズは必ずしも必要ではありません。場合によっては、初期化フェーズの後であることもあります。もう一度始めましょう。これは、Java言語のランタイムバインディング機能(動的バインディングまたは遅延バインディングとも呼ばれます)をサポートすることです。

これらのステージは通常インターリーブされて混合され、通常は1つのステージの実行中に別のステージを呼び出したりアクティブ化したりするため、ここでのステ​​ージは順番に実行または完了するのではなく、順番に開始されます。

ロード:クラスのバイナリデータを検索してロードします。

ロードフェーズ中に、仮想マシンは次の3つのことを完了する必要があります。

  • 1)クラスの完全修飾名を使用して、このクラスを定義するバイナリバイトストリームを取得します。
  • 2)このバイトストリームで表される静的ストレージ構造をメソッド領域のランタイムデータ構造に変換します。
  • 3)メソッド領域でこのクラスのさまざまなデータへのアクセスエントリとしてメモリ内のこのクラスを表すjava.lang.Classオブジェクトを生成します。

画像-20200827112719502

検証:ロードされたクラスが正しいことを確認する

検証は接続フェーズの最初のステップです。このフェーズの目的は、Classファイルのバイトストリームに含まれる情報が現在の仮想マシンの要件を満たし、仮想マシン自体のセキュリティを危険にさらさないことを確認することです。検証フェーズでは、おおよそ4つのフェーズの検査アクションが完了します。

  • ファイル形式の検証:バイトストリームがClassファイル形式の仕様に準拠しているかどうかを検証します。たとえば0xCAFEBABE、開始するかどうか、メジャーバージョン番号とマイナーバージョン番号が現在の仮想マシンの処理範囲内にあるかどうか、定数プール内の定数にサポートされていない型があるかどうかを検証します。
  • メタデータ認証:バイトコード情報セマンティック分析(注:javacコンパイルの比較セマンティック分析フェーズ)を記述します。これは、Java言語仕様の要件への準拠を保証するための情報を記述します。例:親クラスかどうかjava.lang.Object以外。
  • バイトコードの検証:データフローと制御フローの分析を通じて、プログラムのセマンティクスが正当で論理的であると判断されます。
  • シンボル参照の検証:解析アクションを正しく実行できることを確認します。

検証フェーズは非常に重要ですが、必須ではありません。プログラムの実行時間には影響しません。参照されたクラスが繰り返し検証されている場合は、-Xverifynoneパラメーターを使用してほとんどのクラス検証対策をオフにし、仮想マシンクラスのロードを短縮することを検討できます時間。

準備:クラスの静的変数にメモリを割り当て、それらをデフォルト値に初期化します

準備段階は、クラス変数にメモリを正式に割り当て、クラス変数の初期値を設定する段階であり、これらの変数が使用するメモリは、メソッド領域に割り当てられます。

この段階でのメモ:

  • 現時点では、メモリ割り当てには、クラス変数(staticによって変更された変数)のみが含まれ、オブジェクトがインスタンス化されるときにオブジェクトとともにJavaヒープに割り当てられます。
  • 典型的には、ここで初期値セットがゼロ(例えば、デフォルト値のデータ型である00Lnullfalse値はJavaコードで明示的に与えられているのではなく、等)。

例:クラス変数がpublic static int value = 3:; として定義されているとします。Javaメソッドがまだ実行されておらず、値を3 割り当てる命令はプログラムのコンパイル後であるため、準備フェーズ後の変数値の初期値はではあり0ません。これはクラスコンストラクターメソッドに格納されるため、値を3に割り当てるアクションは初期化フェーズで実行されます。3put static()

  • 基本データ型、クラス変数(静的)、およびグローバル変数の場合、明示的に割り当てずに直接使用すると、システムはそれらにデフォルトのゼロ値を割り当てます。ローカル変数の場合、使用する前に明示的に割り当てる必要があります。そうしないと、コンパイル時に渡されません。

  • 同時に変更される定数staticfinal変更される定数の場合、宣言時に明示的に割り当てる必要があります。そうしないと、コンパイル時に渡されません。finalによってのみ変更される定数は、宣言時に明示的に割り当てるか、またはクラスには、初期化時に明示的に値が割り当てられます。つまり、使用する前に明示的に値を割り当てる必要があり、システムはデフォルトのゼロ値を割り当てません。

  • reference配列参照、オブジェクト参照などの参照データ型の場合、明示的に割り当てずに直接使用すると、システムによってデフォルトのゼロ値が割り当てられますnull

  • 配列の初期化時に配列内の各要素に値が割り当てられていない場合、要素には、対応するデータ型に応じてデフォルトのゼロ値が割り当てられます。

  • クラスフィールドのフィールド属性テーブルにConstantValue属性が存在し、これがfinalとstaticの両方によって同時に変更される場合、変数値は準備フェーズでConstValue属性によって指定された値に初期化されます。上記のクラス変数値が次のように定義されているとしますpublic static final int value = 3;。Javacはコンパイル時に値のConstantValueプロパティを生成し、仮想マシンは準備フェーズ中にConstantValue設定に従って値を3に割り当てます。static final定数はコンパイル時にその結果を呼び出し元クラスの定数プールに入れることを理解できます

分析:クラス内のシンボリック参照を直接参照に変換する

解決フェーズは、仮想マシンプロセスの定数プールを直接参照シンボリック参照を置換されている主に分析動作のために、または接口字段类方法接口方法方法类型方法句柄および调用点記号参照7クラスの修飾子。シンボル参照は、ターゲットを説明する一連のシンボルであり、任意のリテラルを使用できます。

直接引用これは、ターゲットを直接指すポインター、相対オフセット、またはターゲットに間接的に配置されたハンドルです。

初期化:クラスの静的変数および静的コードブロックに対して初期化操作を実行します。

初期化とは、クラスの静的変数に正しい初期値を割り当てることです。JVMはクラスの初期化を担当し、主にクラス変数を初期化します。Javaでクラス変数を初期化する方法は2つあります。

  • クラス変数の宣言は初期値を指定することです
  • 静的コードブロックを使用してクラス変数の初期値を指定する

クラス初期化のステップ

  • このクラスがロードおよび接続されていない場合、プログラムは最初にクラスをロードして接続します
  • クラスの直接の親クラスが初期化されていない場合は、直接の親クラスが最初に初期化されます
  • クラスに初期化ステートメントがある場合、システムはこれらの初期化ステートメントを順番に実行します

クラスの初期化をトリガーするタイミング

クラスのアクティブな使用がクラスの初期化につながる場合のみ、クラスのアクティブな使用には次の6つのタイプが含まれます。

  • newキーワードを使用してオブジェクトをインスタンス化する場合。

  • 静的フィールドのタイプの読み取りまたは設定時(finalによって変更され、結果がコンパイル時に定数プールに入れられた静的フィールドを除く)。

  • 型の静的メソッドを呼び出すとき。

  • java.lang.reflectパッケージメソッドを使用して型に対してリフレクション呼び出しを行う場合、型が初期化されていない場合は、最初にその初期化をトリガーする必要があります。

  • クラスを初期化するときに、親クラスが初期化されていないことがわかった場合は、最初に親クラスの初期化をトリガーする必要があります。

  • 仮想マシンが起動すると、ユーザーは実行するメインクラス(main()メソッドを含むクラス)を指定する必要があり、仮想マシンは最初にメインクラスを初期化します。

次の状況では、クラスの初期化は実行されません

  1. サブクラスを介して親クラスの静的フィールドを参照すると、親クラスの初期化のみがトリガーされ、サブクラスの初期化はトリガーされません。

  2. オブジェクトの配列を定義しても、クラスの初期化はトリガーされません。

  3. 定数は、コンパイル時に呼び出し元のクラスの定数プールに保存されます。基本的に、定数を定義するクラスへの直接参照はなく
    、定数が定義されているクラスはトリガーされません

  4. クラス名でClassオブジェクトを取得しても、クラスの初期化はトリガーされません。

  5. Class.forNameを介して指定されたクラスを読み込むときに、指定されたパラメーターの初期化がfalseの場合、クラスの初期化はトリガーされません
    。実際、このパラメーターは仮想マシンにクラスを初期化するかどうかを指示します。

  6. ClassLoaderのデフォルトのloadClassメソッドを通じて、初期化アクションはトリガーされません。

使用する

クラスアクセスメソッド領域のデータ構造のインターフェイス。オブジェクトはヒープ領域のデータです。

アンインストール

Java仮想マシンがそのライフサイクルを終了するいくつかの状況

  • System.exit()メソッドが実行されます
  • プログラムは正常に終了します
  • プログラムの実行中に例外またはエラーが発生し、異常終了しました
  • オペレーティングシステムのエラーにより、Java仮想マシンプロセスが終了しました

おすすめ

転載: blog.csdn.net/kaihuishang666/article/details/108262783