【Java】Javaクラスローディングとクラスローダ

序文

Java のクラス ロード フェーズは、ロード、リンク、および初期化に分けられます。リンク プロセスには、検証、準備、および解決が含まれます。

1.読み込み

クラスのバイトコードをメソッド領域にロードし、内部的にC++のinstanceKclassを使ってJavaクラスを記述する

instanceKclass の重要なフィールド:

  • _java_mirror: Java クラス ミラー。クラス オブジェクトのアドレスを格納します。たとえば、String の場合、String.class を格納します。
  • _super: 親クラス
  • _methods: メソッド
  • _constants: 定数プール
  • _class_loader: クラスローダー
  • _vtable: 仮想メソッド テーブル
  • _itable: インターフェイス メソッド テーブル

ここに画像の説明を挿入

2. リンク

リンクフェーズは验证、准备、初始化3 つの部分で構成されています

確認

クラスが JVM 仕様に準拠していることを確認し、セキュリティ チェックを実行します。たとえば、Java ファイルのマジック ナンバーをチェックします。

準備

静的変数にアドレス空間を割り当て、デフォルト値を設定

  • 静的変数の割り当てと割り当ては 2 つのステップであり、スペースの割り当ては準備段階で完了し、割り当ては初期化段階で完了します。
  • 静的変数が最終型で、変数の型が基本データ型または文字列オブジェクトである場合、準備フェーズで割り当てられます。
  • static 変数が final 型で、変数型が参照オブジェクトの場合、初期化フェーズで割り当てられます。

分析する

定数プール内のシンボリック参照を直接参照に解決します

3. 初期化

call ()v を初期化、つまり、クラスのコンストラクター、コード ブロックなどを実行し、仮想マシンはこのクラスのスレッド セーフを保証します。

タイミング

一言で言えば、クラスの初期化は怠惰です

  • メイン メソッドがあるクラスは常に最初に初期化されます。
  • クラスの静的変数または静的メソッドに初めてアクセスすると、これらの変数は最終的なものではないため、クラスの初期化フェーズで割り当てられます。
  • サブクラスの初期化により、親クラスが初期化されます。
  • サブクラス メソッドの親クラスの静的変数は、親クラスの初期化を引き起こします。
  • Class.forName;
  • new は初期化を引き起こします。

クラスの初期化をトリガーしません

  • アクセス クラスの static final 静的変数 (基本型と文字列) は、これらの変数の割り当てが準備段階にあるため、初期化されません。
  • class object.class はクラスの初期化をトリガーしません。
  • このクラスの配列を作成しても、初期化はトリガーされません。
  • クラスローダーの loadClass メソッド。
  • Class.forNameのパラメータ2がfalseの場合

4. クラスローダー

例としてJDK8を取り上げます

名前 クラスをロードする場所 例証する
ブートストラップ クラスローダー JAVA_HOME/jre/lib 直接アクセス不可
拡張 ClassLoader JAVA_HOME/jre/lib/ext Superior は Bootstrap ClassLoader、アクセスは null
アプリケーションクラスローダー クラスパス 上位はExtension ClassLoader
カスタムクラスローダー カスタムの親 アプリケーション ClassLoader

クラスローダーの役割: クラスのバイナリバイトコードをロードする

親の委任

親委譲モードは、階層的な親子関係を定義する Java クラスのローディング メカニズムであり、適切なクラス ローダーが見つかるまで、親クラス ローダーは要求を下方に委譲します。

  • 最初に、キャッシュをチェックして、ローダーがこのクラスを既にロードしているかどうかを調べます。ロードしていない場合は、親クラスのローダーに移動して見つけます。
  • キャッシュに見つからない場合は、クラス ローダーが上から下に使用されてクラスが作成されます。
  • 最後にこのクラスに戻ります。
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            // 检查缓存,是否已经加载过这个类
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        // 向上级的累加器中找
                        c = parent.loadClass(name, false);
                    } else {
                        // 向 Bootstrap 类加载器中找
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
            	// 如果缓存没有找到,就去创建
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    // 调用 findClass 去创建类
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

おすすめ

転載: blog.csdn.net/u011397981/article/details/130426900