ホームページ >Java >&#&チュートリアル >JVM エスケープ分析を 3 分で理解する
資格のある Java 開発者ならご存知のように、基本的にすべてのオブジェクトはヒープ上に作成されます。ただし、ここにはまだ絶対的な単語はなく、 基本的にすべての を指します。
昨日のインタビュー中に、友人はすべてのオブジェクトはヒープ内に作成されると言い、インタビュアーを笑いました。
それでは本文を始めましょう。今日はエスケープ分析について話しましょう。
エスケープ分析 (エスケープ分析) は、現在、Java 仮想マシンにおける比較的最先端の最適化テクノロジです。これは、Java プログラムにおける同期負荷とメモリ ヒープ割り当ての圧力を効果的に軽減できる、機能横断的なグローバル データ フロー分析アルゴリズムです。 Java ホットスポット コンパイラは、エスケープ分析を通じて、新しいオブジェクトの参照の使用範囲を分析し、このオブジェクトをヒープに割り当てるかどうかを決定できます。
エスケープ分析の基本原則は: オブジェクトの動的スコープを分析することです。オブジェクトがメソッド内で定義されている場合、オブジェクトは渡されるなどの外部メソッドによって参照される可能性があります。他のメソッドへの呼び出しパラメータとして使用することは、メソッド エスケープと呼ばれます。他のスレッドでアクセスできるインスタンス変数への代入など、外部スレッドからアクセスされることもあります。これはスレッド エスケープと呼ばれます。決してエスケープしない場合は、メソッド エスケープと呼ばれます。スレッドエスケープまで、オブジェクトの低レベルから高レベルまでの異なるエスケープレベルと呼ばれます。
エスケープ分析をオンにすると、コンパイラは次のようにコードを最適化できます:
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 サイトの他の関連記事を参照してください。