序文
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;
}
}