JVMの詳細クラスロードの手順
3091 ワード
まず、Javaクラスを作成したときに、このjavaクラスを実行するには、まずjavacコマンドでclassのバイナリファイルと見なし、javaコマンドで実行して結果を得る必要があることを知っています.では、jvmがclassファイルをメモリにロードしている間にどのようなステップが実行されたのか、詳しく説明します.
1.ロード
このフェーズはクラスロードの最初のステップです.ここではクラスの全限定名でクラスのバイナリストリームファイルが取得され、メソッド領域のデータフォーマットに従ってメソッド領域に期間が格納されます(jdk 8にメタデータ領域が格納されます).その後、java.lang.Classオブジェクトがメソッド領域にインスタンス化されます.このオブジェクトプロバイダはメソッド領域の外部インタフェースにアクセスします.このClassオブジェクトは通常のオブジェクトに比べて特殊で、スタックメモリに格納されているわけではありません.また、ロードプロセスと次の検証、準備などのプロセスはシリアルではありません.ロードが開始されていますが、まだ終了していない場合、次のステップはすでに実行されています.
2.検証
この段階は主にclassファイルがjvmの規範に合致するかどうかを検証し、jvmの安全性を確保するためであり、この段階は主にマジック、メタデータなどを検証し、主にclassファイルの規範性と安全性を確保することである.
3.準備
このフェーズでは、クラス内のクラス変数(static修飾変数)を初期化する付与操作を行い、メソッド領域にメモリを割り当てます.説明するのは、このフェーズではクラス変数にjvmで規定されたデフォルト値を付与するだけで、private static int a=666などのユーザー定義変数値は付与されません.このフェーズではintの初期値が付与されます.すなわち0である、この値はputstatic命令の実行後にに格納され、クラスの初期化段階で666として付与されるが、final修飾クラス変数であれば、ここではユーザ定義の値、例えばprivate static final int b=123として直接付与、ここではbを0としない123として付与.
4.解析
このプロセスは多くの複雑なステップに関連していますが、簡単に言えば、解析フェーズで行うことは、クラス内のシンボル参照を直接参照に変換することです.例えばprivate static String name=「lex」であり、この中のnameはシンボル参照であり、このフェーズではnameを実際のアドレスに変換するポインタです.このnameで対応するアドレスの定数プールの「lex」を見つけることができます.
5.初期化
このフェーズでは、準備フェーズで初期化された静的変数に対してもう一度値を割り当てます.今回は、ユーザー定義の値を対応する変数に割り当てます.コンパイラは、クラス内のすべての静的コードブロックを自動的に収集し、クラス変数に対する値付け操作を行い、メソッドに組み合わせて実行します.clinitメソッドについていくつか注意すべき点があります.このメソッドは必ずしも生成されるわけではありません.クラスに静的変数の付与操作と静的コードブロックがなければ、コンパイラはclinitメソッドを生成しません.逆に、静的コードブロックと静的変数の付与操作のいずれかであれば、clinitメソッド を生成します.仮想機会保証サブクラスclinitメソッドが実行される前に、親クラスのclinitメソッドは を実行しました. staticコードブロックはclinitで実行するため、親クラスのclinitはサブクラスよりも前に実行され、すなわち、親クラスの静的コードブロックが先にサブクラスと を実行することを示す.インタフェースにはstaticコードブロックはないが、静的変数の付与も可能であるため、インタフェースにはclinitメソッド もある.仮想マシンはclinit実行の原子性を保証し、複数のスレッドが同時に1つのクラスを初期化すると、1つのスレッドだけがclinitメソッドに実行され、他のスレッドはブロックされますが、clinitを実行するスレッドが終了すると、他のスレッドもこのメソッドを再実行できません.同じクラスローダの下で、1つのタイプは1回のみ に初期化されます.
6.クラス・ロードの全手順を示すまずテストコード を書きます.このクラスをメソッド領域にロードし、対応するclassオブジェクトをメソッド領域 に生成する.関連検証 準備フェーズでは、静的変数が初期化され、name=null、gender=null、num=123となります.numはfinalタイプなので、123として付与されますが、ageは静的変数ではありませんので、 は操作しません.検証フェーズでは、シンボル参照が直接参照 に変換されます.初期化フェーズでは、静的コードブロックと静的変数付与操作をclinitメソッドに組み合わせて実行し、private static String name=「lex」を最初に実行します.の割り当て操作を行い、name=「lex」になり、静的コードブロックの割り当てを続行します.gender=「man」 この時点でクラスロードのフェーズが完了し、mainメソッドの実行が開始され、mainメソッドはメソッドスタック に入る.はnewオブジェクトの操作を実行します.これは、スタックメモリにこのオブジェクトに空間を開き、このスタックメモリにageの値を0 に初期化します.その後ageの値を18 に割り当てる.はその後、initメソッド、すなわち構築メソッド を実行する.
7.静的および非静的アクセスの問題
私たちはコードを書くときに静的が非静的にアクセスできないとよく言いますが、なぜなのかというと、上述したように、静的修飾の変数やメソッドはクラスに属しており、これらはメソッド領域に格納されており、クラス名で直接アクセスすることで、静的インスタンス変数ではなくスタックメモリを指すことはありません.静的インスタンス変数はスタックメモリに格納されています
1.ロード
このフェーズはクラスロードの最初のステップです.ここではクラスの全限定名でクラスのバイナリストリームファイルが取得され、メソッド領域のデータフォーマットに従ってメソッド領域に期間が格納されます(jdk 8にメタデータ領域が格納されます).その後、java.lang.Classオブジェクトがメソッド領域にインスタンス化されます.このオブジェクトプロバイダはメソッド領域の外部インタフェースにアクセスします.このClassオブジェクトは通常のオブジェクトに比べて特殊で、スタックメモリに格納されているわけではありません.また、ロードプロセスと次の検証、準備などのプロセスはシリアルではありません.ロードが開始されていますが、まだ終了していない場合、次のステップはすでに実行されています.
2.検証
この段階は主にclassファイルがjvmの規範に合致するかどうかを検証し、jvmの安全性を確保するためであり、この段階は主にマジック、メタデータなどを検証し、主にclassファイルの規範性と安全性を確保することである.
3.準備
このフェーズでは、クラス内のクラス変数(static修飾変数)を初期化する付与操作を行い、メソッド領域にメモリを割り当てます.説明するのは、このフェーズではクラス変数にjvmで規定されたデフォルト値を付与するだけで、private static int a=666などのユーザー定義変数値は付与されません.このフェーズではintの初期値が付与されます.すなわち0である、この値はputstatic命令の実行後に
4.解析
このプロセスは多くの複雑なステップに関連していますが、簡単に言えば、解析フェーズで行うことは、クラス内のシンボル参照を直接参照に変換することです.例えばprivate static String name=「lex」であり、この中のnameはシンボル参照であり、このフェーズではnameを実際のアドレスに変換するポインタです.このnameで対応するアドレスの定数プールの「lex」を見つけることができます.
5.初期化
このフェーズでは、準備フェーズで初期化された静的変数に対してもう一度値を割り当てます.今回は、ユーザー定義の値を対応する変数に割り当てます.コンパイラは、クラス内のすべての静的コードブロックを自動的に収集し、クラス変数に対する値付け操作を行い、
6.クラス・ロードの全手順を示す
public class Demo {
private static String name="lex";
private static String gender;
private static final num=123;
private Integer age=18;
static{
gender="man";
}
public static void main(String[] args) {
new Demo();
}
}
7.静的および非静的アクセスの問題
私たちはコードを書くときに静的が非静的にアクセスできないとよく言いますが、なぜなのかというと、上述したように、静的修飾の変数やメソッドはクラスに属しており、これらはメソッド領域に格納されており、クラス名で直接アクセスすることで、静的インスタンス変数ではなくスタックメモリを指すことはありません.静的インスタンス変数はスタックメモリに格納されています