JVMの最初から最後までのプロセスを完全に理解する

JVMは最初から最後までどのように体験しますか?

1.クラスをロードします

Javaクラスの場合、最初にクラスファイルにコンパイルされます。仮想マシンがメソッドを実行し、メモリ内にクラスのバイナリ表現がないことを検出すると、クラスローダーを介してクラスのバイナリ表現を検索しようとします。

親の委任メカニズム

同じクラス名を指定すると、いつでも同じクラスにロードできます。これは、親委任マシンを介して実現されます。各クラスローダーには独自のロード戦略があります。HotSpotには複数の組み込みクラスローダーがあります。クラスがクラスローダーがクラスをロードするとき、最初にクラスのロードタスクをその親クラスローダーに引き渡し、レイヤーごとに委任します。親クラスローダーがそれをロードできる場合は、次にロードします。クラスをロードできません。ロードするために子クラスに渡されます。端的に言えば、クラスをロードするとき、親クラスローダーの優先度は子クラスの優先度よりも高くなります。たとえば、Javaに付属しているString型と同じ名前のString型を作成すると、プログラムは起動時にString型をメモリに確実にロードし、クラスがロードされるときにString型をロードします。 。タスクは親クラスに渡されます。率直に言って、Javaに付属しているのはクラスローダーです。彼は自分で記述する代わりに、独自の文字列型をロードします。

2.リンク

このプロセスは、検証、準備、解析の3つのステップに分けることができます(オプション)

確認

この手順では、ロードされたクラスが正しい形式であり、適切にフォーマットされたシンボルテーブルがあり、正しいセマンティクスがあることを確認します。

準備

準備には、仮想マシン内で使用される静的ストレージとデータ構造のためのスペースの割り当てが含まれます

解析(オプション)

解析フェーズの主な内容は、現在のクラスに含まれる他のクラスとインターフェースをロードし、参照が正しいかどうかを確認することです。これは、C言語の「静的」リンクと同様に、再帰的なプロセスです。 、リンクのより「怠惰な」方法もあります-クラスまたはインターフェースは、それらが使用された場合にのみ解決されます。

上記の2つの方法には、それぞれ長所と短所があります。最初の方法は実行前に問題を見つけることができますが、2番目の方法は実行時に見つけることができます。

3.初期化(初期化)

クラスを初期化に初期化する必要があることです。これは再帰的なプロセスです。最も単純なオブジェクトはすべてのクラスのスーパークラスであるため、この再帰的な初期化はObjectで終了します

ロックを初期化します

Javaはマルチスレッドであるため、ロード中の競合を防ぐために、各クラスまたはインターフェースには一意の初期化ロックがあり、このクラスの初期化を示す状態があります。合計は次のとおりです。

  • 検証済みで準備ができており、初期化されていません
  • スレッドによって初期化されています
  • 初期化されており、使用できます
  • エラー状態で、初期化に失敗した可能性があります

スレッドがクラスを初期化しようとすると、最初に初期化ロックを取得し、取得後、特定の状態に応じてロックを解除するか待機するかを決定します。例:このクラスは別のスレッドによって初期化されており、初期化が完了したことが通知されるまで、現在のスレッドは初期化ロックを解放してブロック状態になります。

4.新しいクラスインスタンスの作成

明示的なインスタンス化と暗黙的なインスタンス化

インスタンス化を表示する:

これは比較的単純で、実際、コンストラクターを介してインスタンス化されます

暗黙のインスタンス化:

1. String型を含むクラスまたはインターフェースをロードすると、暗黙的にStringオブジェクトが作成されます

2.戻り型などのボクシング操作。Integerただし、メソッドの最後にreturn 0、ラッパークラスが暗黙的に作成されます。

3.字符串 + String类型操作により、新しいStringオブジェクトが作成されます

4.lambda表达式インターフェースを実装するインスタンスオブジェクトを作成できます

インスタンス化プロセス

クラスのコンストラクターは、インスタンス化プロセス中に呼び出されます。処理プロセスには5つのステップがあります。より複雑なため、ここでは簡単に説明し、例を通してすべての人に理解してもらいます。

1.コンストラクターが実行されるときに、パラメーターがクラスでもある場合、そのコンストラクターが実行されます。たとえば、パラメータがString型の場合、Stringのコンストラクタが最初に実行されます。

2.コンストラクターで特定のロジックを実行する前に、親クラスのコンストラクターが最初に実行されます。これは再帰的なプロセスであり、super()コンストラクター(オブジェクトを除く)が非表示になっていることを意味します。

3.親クラスのコンストラクターを呼び出すとき、サブクラスによってオーバーライドされるメソッドを呼び出すとき、サブクラスが最初に呼び出されます(例を以下に示します)

例一:

class Point {
    
    
    // super(); //隐藏的父类构造方法
    int x, y;
    Point() {
    
     x = 1; y = 1; }
}
class ColoredPoint extends Point {
    
    
    // super(); //隐藏的父类构造方法
    int color = 0xFF00FF;
}
class Test {
    
    
    public static void main(String[] args) {
    
    
        ColoredPoint cp = new ColoredPoint();
        System.out.println(cp.color);
    }
}

実装プロセス

ColoredPoint() --> Point() --> Object() --> 初始化x,y --> Point() --> 初始化color变量

例二:

class Super {
    
    
    Super() {
    
     printThree(); }
    void printThree() {
    
     System.out.println("three"); }
}
class Test extends Super {
    
    
    int three = (int)Math.PI;  // That is, 3
    void printThree() {
    
     System.out.println(three); }

    public static void main(String[] args) {
    
    
        Test t = new Test();
        t.printThree();
    }
}

出力:

0
3

実装プロセス:

1、执行Test()
2、执行Test()中的super(),也就是Super()方法
3、然后执行Super()方法中的super(),也就是Object的构造方法
4、执行Super类的printThree()方法,因为被子类重写了,所以会调用子类的printThree()方法,输出tree变量的值0(是默认值,因为 int three = (int)Math.PI 还没被执行)
5、执行Test类中的 int three = (int)Math.PI 让three的值变为了3
6、再执行Test类中的printThree()方法,此时输出3

5.クラスインスタンスのファイナライズ

オブジェクトにはprotect装飾されたfinalizeメソッドがあります。つまり、どのサブクラスでもスーパークラスのfinalizeメソッドを呼び出すことができます。オブジェクトに到達できない場合(使用されなくなった場合)、オブジェクトはリサイクルされ、その前に、Java仮想マシンがこのメソッドを呼び出します。

特徴

1.finalizeメソッドはJVMが解放できないリソースを解放できるため、オブジェクトが使用するメモリを再利用するだけでは、オブジェクトが所有するすべてのリソースを再利用することはできません。

2.コンストラクターとは異なり、finalize呼び出しは順序付けられません。つまり、オブジェクトのバッチをリサイクルする場合、それらのfinalizeメソッドは任意の順序で呼び出すことができ、複数のスレッドでも同時に呼び出すことができます。

3.コンストラクターとは異なり、JVMはfinalize、プログラムで記述されていない限り、親クラスのメソッドを自動的に呼び出すことはありません。

4.finalizeキャッチされなかった例外がメソッドでスローされた場合、例外は無視されfinalize、メソッドの呼び出しは終了します。次に例を示します。

public class Test {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        testFinalize();
    }

    private static void testFinalize() throws InterruptedException {
    
    
        List<ObjectA> list = new ArrayList<>(10);
        for (int i = 0; i < 5; i++) {
    
    
            list.add(new ObjectA());
        }
        list = new ArrayList<>();
        System.gc();
        Thread.sleep(Long.parseLong("4000"));
        System.out.println("complete!");
    }
}
class ObjectA {
    
    
    @Override
    protected void finalize() {
    
    
        System.out.println("finalize() start");
        // 执行到这里后,因为异常将不会往下执行
        int a = 10 / 0;
        System.out.println("finalize() end");
    }
}

出力:

finalize() start
finalize() start
finalize() start
finalize() start
finalize() start
complete!

6.クラスとインターフェースのアンロード

上記のオブジェクトインスタンスの再利用に加えて、Javaはクラスとインターフェイスをリサイクルすることもできます。つまり、クラスとインターフェイスを「アンロード」します。クラスのアンロードは必要ありません。これは、最初に多くのクラスをロードし、しばらくするとそれらの使用を停止するアプリケーションにのみ意味がある最適化です。

特徴

1.クラスローダーがリサイクルされる場合にのみ、ロードするクラスとインターフェイスをアンロードできます

2.BootStrapLoaderによってロードされたクラスとインターフェースはアンロードできません

7.プログラム終了

プログラムの終了は、次の2つの状況で発生します。

1.デーモン以外のスレッドはすべて終了します

Runtime.getRuntime().exit(n)2.クラスまたはSystem.exit(n)メソッドを呼び出す

おすすめ

転載: blog.csdn.net/weixin_44829930/article/details/121192093