ホームページ  >  記事  >  Java  >  JVM エスケープ分析を 3 分で理解する

JVM エスケープ分析を 3 分で理解する

Java后端技术全栈
Java后端技术全栈転載
2023-08-15 16:39:171219ブラウズ

資格のある Java 開発者ならご存知のように、基本的にすべてのオブジェクトはヒープ上に作成されます。ただし、ここにはまだ絶対的な単語はなく、 基本的にすべての を指します。

昨日のインタビュー中に、友人はすべてのオブジェクトはヒープ内に作成されると言い、インタビュアーを笑いました。

それでは本文を始めましょう。今日はエスケープ分析について話しましょう。

エスケープ分析 (エスケープ分析) は、現在、Java 仮想マシンにおける比較的最先端の最適化テクノロジです。これは、Java プログラムにおける同期負荷とメモリ ヒープ割り当ての圧力を効果的に軽減できる、機能横断的なグローバル データ フロー分析アルゴリズムです。 Java ホットスポット コンパイラは、エスケープ分析を通じて、新しいオブジェクトの参照の使用範囲を分析し、このオブジェクトをヒープに割り当てるかどうかを決定できます。

エスケープ分析の基本原則は: オブジェクトの動的スコープを分析することです。オブジェクトがメソッド内で定義されている場合、オブジェクトは渡されるなどの外部メソッドによって参照される可能性があります。他のメソッドへの呼び出しパラメータとして使用することは、メソッド エスケープと呼ばれます。他のスレッドでアクセスできるインスタンス変数への代入など、外部スレッドからアクセスされることもあります。これはスレッド エスケープと呼ばれます。決してエスケープしない場合は、メソッド エスケープと呼ばれます。スレッドエスケープまで、オブジェクトの低レベルから高レベルまでの異なるエスケープレベルと呼ばれます。

エスケープ分析をオンにすると、コンパイラは次のようにコードを最適化できます:

  1. 同期削除: エスケープ分析によってオブジェクトが見つかった場合、スレッドによってのみアクセスでき、このオブジェクトに対する操作は非同期にすることができます。
  2. スタック上の割り当て: オブジェクトがスレッドからエスケープされないことが確実な場合は、スタック上のオブジェクトにメモリを割り当てることをお勧めします。スタック フレームがポップされると、スペースが破壊される可能性があります。
  3. スカラー置換: オブジェクトがエスケープ解析によって外部メソッドからアクセスできないことが判明し、そのオブジェクトが分解できる場合、プログラムが実際に実行されるときにオブジェクトが作成されない可能性があります。このメソッドではなく、いくつかのメンバー変数を使用して直接作成してください。 オブジェクトを分割した後、オブジェクトのメンバー変数をスタックに割り当て、読み書きすることができます

JVM では、次のパラメータを使用してエスケープ分析を有効にするかどうかを指定できます。

-XX: DoEscapeAnalysis: 示します。そのエスケープは分析で有効になっています (JDK 1.7 以降はデフォルトで有効になっています)。

-XX:-DoEscapeAnalysis: エスケープ分析をオフにすることを示します。

同期の削除

スレッドの同期自体は、比較的時間のかかるプロセスです。エスケープ分析によって、変数がスレッドからエスケープされず、スレッドをエスケープできないことが判明した場合は、他のスレッド アクセスによって使用される場合、この変数の読み取りと書き込みに競合は存在しません。また、この変数に実装された同期手段は安全に削除できます。

次のコードのようなもの:

public void method() {
    Object o = new Object();
    synchronized (o) {
        System.out.println(o);
    }
}

オブジェクト o をロックしますが、オブジェクト o のライフサイクルはメソッド method() と同じであるため、他のスレッドからアクセスされない場合、スレッド セーフティの問題は発生せず、JIT コンパイル フェーズは次のように最適化されます:

public void method() {
    Object o = new Object();
    System.out.println(o);
}

これは、ロック削除 とも呼ばれます。

スタック上の割り当て

Java 仮想マシンでは、オブジェクトを作成するためのメモリ空間がスタック上に割り当てられることは、ほとんどすべての Java プログラマが知っています。 Java ヒープ。常識的には、Java ヒープ内のオブジェクトは共有され、各スレッドから参照できます。このオブジェクトへの参照を保持している限り、ヒープに格納されているオブジェクト データにアクセスできます。仮想マシンのガベージ コレクション サブシステムは、ヒープ内で使用されなくなったオブジェクトをリサイクルしますが、リサイクル可能なオブジェクトのマーク付けとフィルタリング、メモリのリサイクルと整理など、リサイクル アクションには大量のリソースが必要です。ただし、特殊な場合があり、エスケープ解析によりオブジェクトがスレッドの外にエスケープしないことが確認された場合は、スタックへの割り当てが最適化されることがあります。これにより、ヒープ上にメモリを割り当てる必要がなくなり、ガベージ コレクションも必要なくなります。

次のコードのように:

public static void main(String[] args) throws InterruptedException {

    for (int i = 0; i < 1000000; i++) {
        alloc();
    }

    Thread.sleep(100000);
}

private static void alloc() {
    User user = new User();
}

コードは非常に単純です。ループ内で 100 万回作成し、alloc() メソッドを使用して 100 万個の User オブジェクトを作成します。ここで alloc() メソッドで定義された User オブジェクトは他のメソッドから参照されないため、スタック上の割り当ての要件を満たします。

JVM パラメータは次のとおりです:

-Xmx2G -Xms2G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

プログラムを起動し、jmap ツールでインスタンスの数を確認します:

jmap -histo pid

num     #instances         #bytes  class name
----------------------------------------------
1:          3771        2198552  [B
2:         10617        1722664  [C
3:        104057        1664912  com.miracle.current.lock.StackAllocationTest$User

プログラムがユーザー オブジェクトの合計は 104057 で、これは 100 万よりはるかに少ないです。エスケープ分析をオフにして、もう一度見てみましょう:

-Xmx2G -Xms2G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

プログラムを起動し、jmap ツールでインスタンスの数を確認します:

jmap -histo 42928

 num     #instances         #bytes  class name
----------------------------------------------
   1:           628       22299176  [I
   2:       1000000       16000000  com.miracle.current.lock.StackAllocationTest$User

合計 100 万ユーザーであることがわかります。オブジェクトはエスケープ分析をオフにした後に作成されました。比較すると、スタック上の割り当ては、ヒープ メモリの消費と GC において重要な役割を果たします。

スカラー置換

データをより小さなデータに分解して表現できなくなった場合、Java 仮想マシンの元のデータ型 ( int、long、参照型などの数値型はそれ以上分解できないため、これらのデータはスカラーと呼ばれます。対照的に、データを分解し続けることができる場合、それは集合体と呼ばれ、Java のオブジェクトは典型的な集合体です。

エスケープ解析により、オブジェクトがメソッド外ではアクセスされず、このオブジェクトを分解できることが証明された場合、プログラムが実際に実行されるとき、このオブジェクトは作成されず、そのオブジェクトのいくつかが直接作成される可能性があります。 . 代わりにこのメソッドで使用されるメンバー変数。

には次のコードがあります:

public static void main(String[] args) {

    method();
}

private static void method() {
    User user = new User(25);

    System.out.println(user.age);
}

private static class User {

    private int age;

    public User(int age) {
        this.age = age;
    }
}

method()方法中创建User对象,指定age为25,这里User不会被其他方法引用,也就是说它不会逃逸出方法,并且User是可以拆解为标量的。所以alloc()代码会优化为如下:

private static void alloc() {
    int age = 25;

    System.out.println(age);
}

总结

尽管目前逃逸分析技术仍在发展之中,未完全成熟,但它是即时编译器优化技术的一个重要前进方向,在日后的Java虚拟机中,逃逸分析技术肯定会支撑起一系列更实用、有效的优化技术。

以上がJVM エスケープ分析を 3 分で理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はJava后端技术全栈で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。