クラス読み込みのプロセス(読み込み、検証、準備、解決、初期化);クラスローダー(クラスローダーの開始、拡張クラスローダー、アプリケーションクラスローダー、カスタムクラスローダー);親委譲モデル;
1.仮想マシンのクラスローディングメカニズム:
仮想マシンは、クラスを記述するデータをClassファイルからメモリにロードし、データを検証、変換、分析、初期化し、最終的に仮想マシンが直接使用できるJavaタイプを形成します
2.クラスのライフサイクル:
3.クラスを初期化する必要がある5つの状況:
- 4バイトコードの命令new、getstatic、putstatic、またはinvokestaticを検出した場合
- java.lang.reflectパッケージメソッドを使用してクラスへのリフレクトコールを行う場合
- クラスを初期化するときに、親クラスが初期化されていないことがわかった場合は、最初に親クラスの初期化をトリガーする必要があります。
- 仮想マシンの起動時に、ユーザーは実行するメインクラス(main()メソッドを含むクラス)を指定する必要があり、仮想マシンは最初にこのメインクラスを初期化します。
- JDK 1.7の動的言語サポートを使用する場合、java.lang.invoke.MethodHandleインスタンスの最終分析結果がREF_getStatic、REF_putStatic、REF_invokeStaticのメソッドハンドルであり、このメソッドハンドルに対応するクラスが初期化されていない場合は、最初にトリガーする必要があります。その初期化。
4.見積もり
アクティブな参照:クラスを初期化する必要がある5つの状況での動作。
パッシブリファレンス:5つのケースを除いて、クラスを参照するすべてのメソッドは初期化をトリガーしません
5.クラスローディングのプロセス
Java仮想マシンでのクラスのロードプロセス全体、つまり、ロード、検証、準備、解析、初期化の5つの段階
5.1読み込み
ロードフェーズ中に、仮想マシンは次の3つのことを完了する必要があります。
- 1)このクラスを完全修飾名で定義するバイナリバイトストリームを取得します。
- 2)このバイトストリームで表される静的ストレージ構造をメソッド領域のランタイムデータ構造に変換します。
- 3)メソッド領域内のこのクラスのさまざまなデータへのアクセスポイントとして、メモリ内のこのクラスを表すjava.lang.Classオブジェクトを生成します。
5.2検証
検証は接続フェーズの最初のステップです。このフェーズの目的は、クラスファイルのバイトストリームに含まれる情報が現在の仮想マシンの要件を満たし、仮想マシン自体のセキュリティを危険にさらさないことを確認することです。
検証段階では、通常、ファイル形式の検証、メタデータの検証、バイトコードの検証、およびシンボル参照の検証の4つの検証アクションの段階を完了します。
- 1.ファイル形式の検証:バイトストリームがClassファイル形式の仕様に準拠しており、仮想マシンの現在のバージョンで処理できるかどうかを検証します。例:マジック番号0xCAFEBABEで開始するかどうか。メジャーバージョン番号とマイナーバージョン番号が現在の仮想マシンの処理範囲内にあるかどうか。
- 2.メタデータの検証:バイトコードで記述された情報に対してセマンティック分析を実行し、記述された情報がJava言語仕様の要件を満たしていることを確認します。例:このクラスには親クラスがありますか、このクラスの親クラスは継承が許可されていないクラスを継承しますか
- 3.バイトコードの検証:データフローと制御フローの分析により、プログラムのセマンティクスが正当で論理的であると判断されます。クラスのメソッド本体がチェックおよび分析され、チェックされたクラスのメソッドが、実行時に仮想マシンのセキュリティを危険にさらすイベントを発生させないようにします
- 4.シンボル参照の検証:仮想マシンがシンボル参照を直接参照に変換するとき、それはクラス外の情報(定数プール内のさまざまなシンボル参照)の一致チェックと見なすことができます
ps:実装段階では、-Xverify:noneパラメーターを使用して、ほとんどのクラス検証対策をオフにして、仮想マシンのクラス読み込み時間を短縮することを検討できます。
5.3準備
準備フェーズは、公式クラス変数であり、セットのためのメモリを割り当て、クラス変数プロセスに割り当てられたメモリ領域で使用されるこれらの変数の初期値の段階
5.4分析
解決フェーズは、仮想マシンが定数プール内のシンボル参照を直接参照に置き換えるプロセスです
シンボル参照(シンボリック参照):シンボル参照は、参照されるターゲットを記述するために一連のシンボルを使用します。シンボルは、あいまいさなしにターゲットを見つけるために使用できる限り、任意の形式のリテラルにすることができます。
直接参照:直接参照は、ターゲットへの直接ポインター、相対オフセット、またはターゲットに間接的に配置できるハンドルにすることができます。
解決アクションは主に、クラスまたはインターフェイス、フィールド、クラスメソッド、インターフェイスメソッド、メソッドタイプ、メソッドハンドル、呼び出しポイント修飾子など、7種類のシンボル参照用です。
定数プールのCONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、CONSTANT_MethodType_info、CONSTANT_MethodHandle_info、CONSTANT_InvokeDynamic_infoに対応する7つの定数タイプ
5.5初期化
前のクラス読み込みプロセスでは、読み込みフェーズ中にユーザーアプリケーションがカスタムクラスローダーを介して参加できることを除いて、残りのアクションは仮想マシンによって完全に支配され、制御されます。クラスで定義されたJavaプログラムコード(またはバイトコード)が実際に実行されるのは、初期化段階のみです。
初期化フェーズは、クラスコンストラクター<clinit>()メソッドを実行するプロセスです。
6.クラスローダー
仮想マシン設計チームは、実装するJava仮想マシンの外部のクラスロードフェーズで「クラスの完全修飾名を通じてこのクラスを記述するバイナリバイトストリームを取得する」というアクションを実行し、アプリケーションがすべてを取得する方法を決定できるようにします必須クラス。このアクションを実装するコードモジュールは、「クラスローダー」と呼ばれます。
どのクラスでも、それをロードするクラスローダーとクラス自体によって、Java仮想マシンで一意性を確立する必要があります。各クラスローダーには、独立したクラス名前空間があります。
クラス「等しい」には、クラスを表すClassオブジェクトのequals()メソッド、isAssignableFrom()メソッド、isInstance()メソッドの戻り結果が含まれます。また、instanceofキーワードを使用してオブジェクトの所有権関係を決定することも含まれます。
6.1クラスローダーの分類:
Java仮想マシンの観点から:
- ブートクラスローダー(Bootstrap ClassLoader)。このクラスローダーはC ++言語で実装され、仮想マシン自体の一部です。
- Java言語で実装されている他のすべてのクラスローダーは、仮想マシンの外部から独立しており、すべて抽象クラスjava.lang.ClassLoaderから継承します。
Java開発者の観点から:
- クラスローダーを起動します(Bootstrap ClassLoader):
- 拡張ClassLoader(拡張ClassLoader):
- アプリケーションClassLoader:
6.2親委任モデル
上の図のクラスローダー間の階層関係は、クラスローダーの親の委任モデルと呼ばれます。
6.3親委任モデルの作業プロセス:
クラスローダーがクラスのロード要求を受け取った場合、クラスローダーはそれ自体ではクラスのロードを試みませんが、この要求を親クラスローダーに委任して完了させます。これはクラスローダーのすべてのレベルに当てはまるため、すべてののロード要求は、最終的にはトップレベルのスタートアップクラスローダーに転送されます。親ローダーがロード要求を完了できない(必要なクラスが検索範囲に見つからない)と報告された場合にのみ、子ローダーは自身を試行します。ロードする。
免責事項:この記事は個人的な研究ノートであり、内容は「Java仮想マシンの詳細な理解・JVMの高度な機能とベストプラクティス」周Zhimingとネットワークの記事