ホームページ  >  記事  >  Java  >  Java でのエスケープを理解する方法

Java でのエスケープを理解する方法

WBOY
WBOY転載
2023-04-28 19:19:04818ブラウズ

Java コンパイル システムでは、Java ソース コード ファイルをコンピュータで実行可能な機械命令に変換するプロセスには 2 つのコンパイル段階が必要です。最初の段階では、.java ファイルを .class ファイルに変換します。コンパイルの第 2 段階は、.class をマシン命令に変換するプロセスです。

コンパイルの最初のセクションは javac コマンドです。

2 番目のコンパイル段階では、JVM はバイトコードを解釈して対応する機械命令に変換し、それを 1 つずつ読み込み、変換を 1 つずつ解釈します。明らかに、解釈および実行後の実行速度は、実行可能なバイナリ バイトコード プログラムよりも必然的に大幅に遅くなります。これは従来の JVM インタプリタ (Interpreter) の機能です。この効率の問題を解決するために、JIT (Just In Time Compilation) 技術が導入されました。

JIT テクノロジの導入後も、Java プログラムはインタプリタを介して解釈および実行されますが、JVM は、特定のメソッドまたはコード ブロックが特に頻繁に実行されることを検出すると、それを「ホット スポット コード」と見なします。次に、JIT はいくつかの「ホット コード」をローカル マシンに関連するマシン コードに変換し、最適化して、次に使用するために変換されたマシン コードをキャッシュします。

JIT コンパイルとホットスポット検出の内容については、Java コンパイル原理の徹底分析で紹介したので、ここでは詳しく説明しませんが、ここでは主に JIT における最適化について紹介します。 JIT 最適化の最も重要な側面の 1 つはエスケープ分析です。

脱出分析

エスケープ分析の概念に関しては、すべてのオブジェクトと配列がヒープ上にメモリを割り当てるわけではないという事実を参照できます。 1 つの記事の簡単なレビューです:

エスケープ分析の基本的な動作は、オブジェクトの動的スコープを分析することです。オブジェクトがメソッドで定義されている場合、メソッドと呼ばれる呼び出しパラメーターとして他の場所に渡されるなど、外部メソッドによって参照される可能性があります。逃げる。

たとえば、次のコード:

public static StringBuffer craeteStringBuffer(String s1, String s2) {

StringBuffer sb = new StringBuffer();

sb.append(s1);

sb.append(s2);

sb;

を返す }

public static String createStringBuffer(String s1, String s2) {

StringBuffer sb = new StringBuffer();

sb.append(s1);

sb.append(s2);

sb.toString();

を返す }

最初のコードの sb はエスケープされますが、2 番目のコードの sb はエスケープされません。

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

1. 同期は省略されます。オブジェクトが 1 つのスレッドからのみアクセス可能であることが判明した場合、このオブジェクトに対する操作では同期が考慮されない可能性があります。

2. ヒープ割り当てをスタック割り当てに変換します。オブジェクトへのポインタが決してエスケープしないようにオブジェクトがサブルーチンに割り当てられている場合、そのオブジェクトはヒープ割り当てではなくスタック割り当ての候補となる可能性があります。

3. オブジェクトを分離するか、スカラーを置換します。オブジェクトによっては、アクセスするために連続メモリ構造として存在する必要がない場合があるため、オブジェクトの一部 (またはすべて) がメモリに格納されず、CPU レジスタに格納される場合があります。

Java コードの実行中に、JVM パラメーター

を通じてエスケープ分析を有効にするかどうかを指定できます。 -XX: DoEscapeAnalysis: エスケープ分析をオンにすることを示します

-XX:-DoEscapeAnalysis: エスケープ解析をオフにすることを示します。jdk 1.7 以降、デフォルトでエスケープ解析が開始されます。オフにしたい場合は、-XX:-DoEscapeAnalysis

を指定する必要があります。 同期は省略されました

同期ブロックを動的にコンパイルする場合、JIT コンパイラーはエスケープ解析を使用して、同期ブロックが使用するロック オブジェクトが 1 つのスレッドによってのみアクセス可能であり、他のスレッドに解放されていないかを判断できます。

この分析により、同期ブロックで使用されるロック オブジェクトが 1 つのスレッドによってのみアクセス可能であることが確認された場合、JIT コンパイラーは同期ブロックのコンパイル時にコードのこの部分を非同期化します。この同期を取り消すプロセスは同期省略と呼ばれ、ロックの削除とも呼ばれます。

次のコードのような:

public void f() {

オブジェクトホリス = new Object();

同期(ホリス) {

System.out.println(hollis);

}

}

hollis オブジェクトはコード内でロックされていますが、hollis オブジェクトのライフサイクルは f() メソッド内にのみ存在し、他のスレッドからアクセスされないため、JIT コンパイル フェーズ中に最適化されます。最適化:

public void f() {

オブジェクトホリス = new Object();

System.out.println(hollis);

}

したがって、synchronized を使用する場合、JIT がエスケープ分析後にスレッドの安全性に問題がないことを検出すると、ロックが削除されます。

スカラー置換

スカラーとは、より小さなデータに分割できないデータを指します。 Java のプリミティブ データ型はスカラーです。対照的に、分解可能なデータは集合体と呼ばれ、Java のオブジェクトは他の集合体やスカラーに分解できるため、集合体と呼ばれます。

JIT 段階では、エスケープ解析によりオブジェクトが外部からアクセスされないことが判明した場合、JIT 最適化後、オブジェクトはそれに含まれる複数のメンバー変数に分解され、置き換えられます。この処理がスカラー置換です。

public static void main(String[] args) {

alloc();

}

private static void alloc() {

ポイント point = 新しいポイント(1,2);

System.out.println("point.x=" point.x "; point.y=" point.y);

}

クラスポイント{

プライベート int x;

private int y;

}

上記のコードでは、point オブジェクトは alloc メソッドをエスケープせず、point オブジェクトはスカラーに逆アセンブルできます。次に、JIT は Point オブジェクトを直接作成せず、2 つのスカラー int x と int y を直接使用して Point オブジェクトを置き換えます。

スカラー置換後の上記のコードは次のようになります:

private static void alloc() {

int x = 1;

int y = 2;

System.out.println("point.x=" x "; point.y=" y);

}

集合量 Point のエスケープ分析後、エスケープしないことが判明したため、2 つの集合量に置き換えられたことがわかります。では、スカラー置換にはどのような利点があるのでしょうか?つまり、ヒープ メモリの使用量を大幅に削減できます。オブジェクトを作成する必要がなくなると、ヒープ メモリを割り当てる必要もなくなるためです。

スカラー置換は、スタック上での割り当ての適切な基礎を提供します。

スタック上の割り当て

Java 仮想マシンでは、オブジェクトに Java ヒープ内のメモリが割り当てられることは周知の事実です。ただし、特殊な場合があります。つまり、エスケープ分析後にオブジェクトにエスケープ メソッドがないことが判明した場合、そのオブジェクトはスタック上の割り当てに最適化されることがあります。これにより、ヒープにメモリを割り当てる必要がなくなり、ガベージ コレクションも必要なくなります。

スタックへの割り当ての詳細については、「すべてのオブジェクトと配列がヒープにメモリを割り当てるわけではない」を参照してください。 。

ここで、既存の仮想マシンでは実際にはスタックへの割り当てが実装されておらず、オブジェクトや配列がすべてヒープ上に割り当てられるわけではないことについて簡単に述べておきたいと思います。この例では、オブジェクトはヒープ上に割り当てられておらず、実際にはスカラー置換によって実装されています。

エスケープ分析が成熟していない

エスケープ解析に関する論文は 1999 年に発表されましたが、実装されたのは JDK 1.6 であり、このテクノロジはまだあまり成熟していません。

根本的な理由は、エスケープ分析によるパフォーマンス消費がその消費よりも大きくなるという保証がないことです。ただし、エスケープ解析ではスカラー置換、スタック割り当て、ロックの削除を行うことができます。ただし、脱出分析自体も一連の複雑な分析を必要とし、実際には比較的時間のかかるプロセスです。

極端な例では、エスケープ分析の結果、エスケープしないオブジェクトがないことが判明します。そうなると、エスケープ分析のプロセスが無駄になります。

この技術はあまり成熟していませんが、ジャストインタイムのコンパイラ最適化技術においては非常に重要な手段でもあります。

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

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