一般に、新しいオブジェクトはすべてヒープに割り当てられていると考えられていますが、これは完全に正しくありません。 Javaオブジェクト割り当てプロセスの分析を通じて、ヒープに割り当てられることに加えて、オブジェクトはスタックまたはTLABのスペースを割り当てることもできます。スタックにオブジェクトを割り当てるための技術的根拠は、エスケープ分析とスカラー置換です。この記事では、主に脱出分析を紹介します。
脱出分析の定義
Escape Analysisは、Javaプログラムの同期負荷とメモリヒープの割り当て圧力を効果的に減らすことができる、官能的なグローバルデータフロー分析アルゴリズムです。
エスケープ分析により、Java Hotspotコンパイラは、新しいオブジェクトの参照の使用範囲を分析し、オブジェクトをヒープに割り当てるかどうかを決定できます。
Javaは、Java SE 6U23以降のバージョンで脱出分析オプションをサポートおよび有効にします。 JavaのホットスポットJITコンパイラは、メソッドが過負荷または動的にロードされたときに、コードのエスケープ分析を実行できます。
エスケープ分析の基本的な動作は、オブジェクトの動的範囲を分析することです。オブジェクトがメソッドで定義されている場合、外部メソッドで参照される場合があります。
メソッドエスケープ:たとえば、呼び出しパラメーターとして他のメソッドに渡します。
スレッドエスケープ:他のスレッドでアクセスできるクラス変数やインスタンス変数に値を割り当てるなど、外部スレッドによってアクセスされる場合があります。
脱出分析の理論的根拠
エスケープ分析は、ジョン・デオク・チェ、マニッシュ・グプタ、マウリシオ・セファノ、ヴグラマム・C・スリーダー、サム・ミッドキフなどによって記述されたアルゴリズムに基づいて実行されます。
このアルゴリズムは接続されたグラフを導入し、接続されたグラフを使用してオブジェクトとオブジェクトの参照の間のアクセス可能な関係を構築し、これに基づいて、複合データフロー分析方法が提案されています。アルゴリズムはコンテキスト依存性でストリームに敏感であり、オブジェクトのあらゆるレベルでネストされた関係をシミュレートするため、分析の精度は高くなりますが、実行時間とメモリの消費は比較的大きいです。
エスケープ分析のほとんどの実装は、「閉鎖世界」の前提に基づいています。実行されるすべての可能な方法は、脱出分析の前に知られており、プログラムの実際の操作はそれらの間のコール関係を変更しません。しかし、実際のJavaプログラムが実行された場合、そのような仮定は真実ではありません。動的なクラスの読み込み、ローカル機能の呼び出し、プログラムへの反映などのJavaプログラムの多くの機能は、いわゆる「閉鎖世界」条約を破ります。
エスケープ分析後の処理操作
脱出分析の後、オブジェクトの3つの可能な脱出状態を取得できます。
GlobalEscape:つまり、オブジェクトの参照はメソッドまたはスレッドを逃がします。たとえば、オブジェクトの参照はクラス変数にコピーされるか、脱出したオブジェクトに保存されるか、オブジェクトの参照がメソッドの返される値として呼び出し方式に返されます。
Argescape(パラメーターレベルエスケープ):つまり、メソッドコールプロセス中にメソッドに渡されたオブジェクトの適用。この状態は、チューニングされているメソッドのバイナリコードを分析することで決定できます。
Noescape:スカラーに置き換えることができるオブジェクト。オブジェクトは、従来のヒープに割り当てられない場合があります。
コンパイラは、エスケープ分析の結果を使用して、プログラムを最適化できます。
ヒープ割り当てオブジェクトは、スタック割り当てオブジェクトになります:メソッド内のオブジェクト、およびオブジェクト参照が逃げられないため、このメソッドはスタックメモリに割り当てられ、ヒープメモリに非常に一般的です。
同期を排除する:スレッドの同期のコストは非常に高く、同期の結果は並行性とパフォーマンスを低下させます。エスケープ分析では、オブジェクトが常に1つのスレッドのみでアクセスされるかどうかを判断できます。 1つのスレッドのみでアクセスされる場合、オブジェクトの同期操作は、同期保護なしで操作に変換でき、これにより、並行性とパフォーマンスの程度を大幅に改善できます。
ベクトル置換:エスケープ分析方法オブジェクトのメモリストレージ構造を継続的に実行する必要がないことがわかった場合、CPUレジスタ内のすべてのオブジェクトを保存することができます。