JVMまとめ(2)JVMのクラスリーダー

5479 ワード

javaソースコードのコンパイル後に作成したクラスファイルはどうやってJVMに行きますか?はい、つまりClass loaderが彼女たちをJVMにロードしました。
続いて、3つの方面からClass loaderに対して説明を行います。Class loaderのロードプロセス;Class loaderの原理と分類。
1.lassloaderのタイミング
クラスのライフサイクル:ロード、検証、準備、解析、初期化、使用、アンインストール。
検証、準備、解析の3段階は接続と呼ぶことができる。
なお、上記の段階では開始時間は前後していますが、各段階は通常交差して実行されます。
いつ一つの種類をロードしますか?仮想マシン仕様では、4つの初期化段階のトリガタイミングが明確に規定されています。
1)new、getstatic、putstaticまたはinvokestaticの4バイトコードコマンドに遭遇した場合、クラスが初期化されていない場合は、まず初期化をトリガする必要があります。4つのコマンドを生成するために最も一般的なjavaコードシーンは、newオブジェクトの場合、Stticフィールドを読んだり設定したりする場合(final staticを除く)、クラスのstaticメソッドを呼び出すときです。
2)java.lang.reflectパッケージを使用してクラスを反射呼出しする場合。
3)1つのクラスを初期化すると、親が初期化されていない場合、先に親クラスを初期化する。
4)jvm起動時には、アプリ実行のエントリ(mainを含むクラス)が先に初期化されます。
以上の4つのシーンは、1つのクラスに対するアクティブな参照と呼ばれ、それ以外は受動的な参照であり、初期化動作をトリガすることはない。
1)親タイプの静的フィールドをサブクラスで参照すると、サブクラス初期化の原因になりません。
2)配列定義によるクラス参照は、クラスの初期化をトリガしません。
3)定数(static final)はコンパイル段階でコールクラスの定数プールに預け入れられます。本質的には定義された定数のクラスに直接引用されていません。クラスの初期化をトリガしません。
注意:インターフェースとクラスは異なるところがあります。一つのクラスが初期化する前に、すべての親タイプに初期化を要求しますが、インターフェースは初期化する時、その親インターフェースが全部初期化されることを要求しません。本当の親インターフェース(参照インターフェースで定義された定数など)を使う時に初期化されます。
2.Class loaderのロードプロセス
1)クラスローディング:
ステップ:(1)このようなバイナリストリームを定義するために、クラスの全限定名来を通じて取得する。
      (2)このバイトストリームに代表される静的記憶構造を、方法領域の動作時データ構造に変換する。
      (3)javaスタックの中で、このクラスを表すjava.lang.lassオブジェクトを生成し、方法エリアデータの操作の入り口とします。
ここで、ロードされたクラスは、例えば、ZIPなどのclassファイルパッケージから読み込むソースがたくさんあります。動作時に生成される、例えば動的エージェントによって生成されるエージェントクラス。他のファイルから作られたクラスがあります。JSPアプリケーションなどです。
2)接続:接続はまた以下のステップに分けられます。
(1)検証:
検証は接続段階の第一歩であり、classファイルのバイトフローがJVM仕様に適合することを確保するためである。通常は4段階の検証プロセスがあります。ファイル形式の検証、メタデータの検証、バイトコードの検証、参照の検証に適合します。
1)ファイルフォーマットの検証:Classファイルの標準フォーマットに合致しているかどうか、方法エリアに入ることができます。
2)メタデータの検証:Java言語規範の要求に合致するかどうかは、主にバイトコードの意味分析を行う。
3)バイトコードの検証:クラスの方法体を検証し、主にデータフローと制御フローの分析を行う。
4)引用検証に適合する:最後の段階の検査はJVMが参照に適合して直接参照に変換する(以下に言及する)時に発生する。
(2)準備:この段階は正式にクラス(staticですが、final static--は直接的に番号の後の値を賦与します。除外)変数はメモリを割り当ててクラス変数のデフォルト値を設定します。
(3)解析:定数プール内の該当参照(メモリとは関係ない記号記号記号のみ)を直接参照(メモリアドレスの参照)に変換します。解析の動作は主にクラスまたはインターフェース、フィールド(static)、クラス方法(static方法)、インターフェース方法の4種類について参照に適合し、それぞれ定数プールのCONSTANT_に対応する。クラスinfo,CONSTANT_Fieldref_info,CONSTANT_Methodref_info及びCONSTANT_INterfaceMethodref_infoの4種類の定数タイプ。
  
3)クラスの初期化:クラスの静的変数(static)を正しい初期値に与え、この初期値は開発者自身が定義した時に与えられた初期値で、標準値ではない。
クラスの初期化段階はクラスローディングの最後のステップであり、前のクラスローディング過程では、ローディング段階のユーザーアプリケーションがカスタマイズクラスローダーを通じて参加できる以外、他の作業はJVMが主導して制御しています。初期化段階になって、クラスで定義されているJavaプログラムコードを実行するようになりました。
3.類キャリアの分類
注意:どのクラスに対しても、このクラス自体と一緒にJava仮想マシンにおいて一意性を確立する必要があります(つまり、同じクラスのファイルでも、異なるクラスのクラスの場合は、JVMにおいて2つの種類です)。
1)両親の委任モデルに適合する種類のキャリア
主に三つの種類に分けられます。
(1)始動類キャリア(Bootstrap Class Loader)
このクラスのキャリアは%JAVA_に置きます。HOME%/libディレクトリの中の、または-Xboot classpathパラメータによって指定されたパスの中の、仮想マシン識別のクラスライブラリがJVMメモリにロードされます。ブートクラスのキャリアはJavaプログラムで直接使用できません。
(2)拡張類キャリア(Extension Class Loader)
このクラスのキャリアはsun.misc.Launcher$Ext Class Loaderによって実現され、JAVA_をロードする責任があります。HOME%/lib/extディレクトリの中の、またはjava.ext.dirsシステム変数によって指定された経路のすべての種類のライブラリを開発者が直接に使用することができます。
(3)アプリケーションクラスキャリア(Application Class Loader)
このクラスのキャリアはsun.misc.Launcher$ApClass Loaderで実現されます。このクラスのキャリアは、Class Loaderのget System Class Loader()メソッドの値なので、一般的にはシステムクラスのキャリアにもなります。これはユーザーパスで指定されたクラスライブラリをロードする責任があります。開発者は直接にこのクラスのキャリアを使うことができます。もしアプリケーションに自分のクラスのキャリアをカスタマイズしたことがないなら、通常は、これがプログラムのデフォルトクラスのキャリアです。
両親はモデルを任命して、トップクラスの起動類のキャリアを除いて、他のクラスのキャリアはすべて自分の父類のキャリアを持つべきです。ここの親子関係は組合を通じて実現されます。
作業過程:もし1つのクラスのキャリアがクラスローディングの要求を受け取ったら、それはまず自分でこのクラスをローディングしようとしないで、この要求を親クラスのキャリアに任せて完成させます。各階層のクラスのキャリアは全部このようです。したがって、すべてのローディング要求は最終的にトップレベルの起動クラスのキャリアに転送されます。親キャリアが自分にフィードバックしてこのローディング要求を完了できない場合にのみ、サブキャリアは自分でローディングを試みることができます。
両親がモデルを任命して対応してjavaプログラムの安定運行を保証することは重要ですが、彼の実現はとても簡単で、コードはjava.lag.lassLoaderのloadClassに集中しています。
   
protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    try {
		if (parent != null) {
		    c = parent.loadClass(name, false);
		} else {
		    c = findBootstrapClass0(name);
		}
	    } catch (ClassNotFoundException e) {
	        // If still not found, then invoke findClass in order
	        // to find the class.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }
実行ロジック:先にロードされたかどうかを確認してください。もしなかったら、親キャリアのloadClassを呼び出します。父キャリアが空の場合は、デフォルトの起動クラスのキャリアを父のキャリアとして使用します。父キャリアローダーが失敗したら、自分のfindClassを呼び出します。
2)OSIの類キャリア
OGiはモジュール化熱配置を実現するための鍵として、カスタマイズされたクラスキャリアの実現である。各プログラムモジュールには自分のクラスのキャリアがあります。Bunndleを交換する必要がある時は、Bundeleを同類のキャリアと一緒に交換して、コードの熱交換を実現します。
OSI環境下では、クラス加載器は両親に委任されたモデルの樹状構造ではなく、さらに網状構造に発展し、クラスローディング要求を受けると、OSIは次のような順序で種類の検索を行います。
(1)Java.*で始まるクラスは、親のキャリアに負荷をかけるように委任します。
(2)リストリスト(org.osgi.frame ebook.boot delegation)内のクラスに委任し、親のキャリアローダーに委任する。
(3)Import-packageリストのクラスを、Exportという種類のBundeleのクラスキャリアにロードするように委任する;
(4)Required-Bundeleリストのクラスを、それぞれの種類の対応するBunndleのクラスのキャリアローディングを委任する。
(4)現在のBundeleのクラスパスパスを探して、自分のクラスのキャリアを使ってロードします。
(5)ルックアップクラスは、自分のフラジャイティ・バーストの中にあるかどうか、もしいるなら、フラジャイティ・バーストのクラスキャリアにロードするように委任します。
(6)Dynamic Import(動的導入)リストのBundelを検索し、Bunndleに対応するクラスローディングを委任する。
(7)さもなければクラス検索に失敗しました。