Jump to content 日本-日本語
日本HPホーム 製品 & サービス サポート & ドライバー ソリューション ご購入方法
≫  お問い合わせ

製品とサービス  >  ソフトウェアとOS  >  HP-UX   >  Knowledge-on-Demand  >  Javaパフォーマンス・チューニング

Javaパフォーマンス・チューニング

第6回:メモリ・リーク解析とHotSpot JVM

HP-UX/Integrityサーバー お問い合せ
コンテンツに進む
メモリ・リーク解析とHotSpot JVM
Javaパフォーマンス・チューニング 第6回
HPjmeterによるメモリ・リーク解析
HotSpot JVMの特性を知る
ページ:  戻る   |   1   2

HotSpot JVMの特性を知る


後半では、Javaパフォーマンス・チューニングの仕上げとして、HotSpot JVMに固有のふるまいを学びます。HotSpot JVMではパフォーマンスを改善できないケースを明らかにし、その対象方法を説明します。

アプリケーションのチューニングの効果を比較するためにしばしば作成されるのが、簡単なベンチマーク・プログラムです。しかし、HotSpotベースのJVMでは、ベンチマークの設計のまずさが誤解を生む原因となりかねません。たとえば、ベンチマークによっては、旧型のJIT(Just-In-Time)コンパイラを備えたClassic JVMの方が高速になることもあるのです。

まずは、以下のベンチマークを見てください。

public class SimpleBenchmark {
   public static void main(String[] argv) {
      int value=0;

      // Record the start time.
      long start= System.currentTimeMillis();

      // Repeatedly executes feature to measure performance.
      for (int i=0; i<100000000; i++) {
         // Replace line with your favorite computation.
         value +=i;
      }

      // Record the finish time.
      long finish= System.currentTimeMillis();

      // Now report how long test ran.
      System.out.print ("Time spent = " +
      Long.toString(finish - start) + " ms\n");
   }
}

ご覧のとおり、ループを10億回繰り返し、その経過時間を計るという簡単なベンチマークです。このプログラムをコンパイルし、デフォルトのHotSport JVMで実行すると、以下のような結果が得られます。

$ /opt/java1.3/bin/java SimpleBenchmark
Time spent = 24168 ms

一方、JVMの起動オプションに-classicを指定し、Classic JVMで実行してみます。

$ /opt/java1.3/bin/java -classic SimpleBenchmark
Time spent = 911 ms

このように、HotSpot JVMはClassic JVMよりも25倍も遅いという結果が得られます。

ここで、JITコンパイルを一切行わず、すべてをインタプリタ実行するとどのような結果が得られるか、試してみましょう。HP JVMでは、-Xintオプションを指定することで、純粋なインタプリタとしてJVMを動作させることができます。その結果は以下の通りです。

$ /opt/java1.3/bin/java -Xint SimpleBenchmark
Time spent = 24100 ms

このように、上述したHotSpot JVMによる結果は、インタプリタ実行時の結果とほぼ同じであることがわかります。


HotSpot JVMとClassic JVM


では、なぜこのような違いが表れるのでしょうか。その理由を探るために、HotSpot JVMとClassic JVMの差を比較してみます。

Classic JVM

JIT(Just-In-Time)コンパイラを搭載する。実行されるすべてのコードをコンパイルする

HotSpot JVM

HotSpotコンパイラを搭載する。アプリケーションにおいてもっとも実行頻度の高い部分のみコンパイルする

一般的なプログラムでは、コードの20%の部分に実行時間の80%が費やされるという、いわゆる80/20の法則が当てはまります。HotSpot JVMは、この80/20の法則に基づいて設計されています。つまり、同JVMでは最初はアプリケーションをインタプリタ・モードで実行し、コードの実行頻度の解析を行います。これにより、「HotSpot」すなわち実行頻度の高い部分を特定したならば、その部分についてのみバイナリ・コードへのコンパイルやインライン展開などの最適化を実施します。これに対し、Classic JVMでは、実行されるすべてのコードをコンパイルするため、コンパイル時間がオーバーヘッドとなります。

本来であれば、HotSpot JVMの方がClassic JVMよりも優れたパフォーマンスを実現できるはずです。しかし、上述したベンチマークの例では、ループを含むメソッドが1回しか呼び出されないため、インタプリタ・モードのままループを実行してしまうのです。

こうした場合は、HP JVMの起動オプションとして-XX:+UseOnStackReplacementを指定し、On Stack Replacement機能を有効にします*。同機能を利用すると、メソッド呼び出しの最中でも、インタプリタ・モードからコンパイルされたバイナリ・コードの実行に切り替えられるようになります。

*この機能を有効にするためには、現時点ではパッチ (HPUX11.0:PHKL_24943, HP-UX11i PHKL_24751 )が必要です。また同時に、コンパイラのセーフポイント機能も有効にする必要があります(-XX:+UseCompilerSafepoints)。詳細はSDK 1.3.1.02 以降のリリースノートを参照してください。

このオプションを指定して先のベンチマークを実行すると、以下のようになります。

$/opt/java1.3/bin/java
  -XX:+UseCompilerSafepoints
  -XX:+UseOnStackReplacement SimpleBenchmark
Time spent = 42 ms

このように、Classic JVMより優れた結果が得られることがわかります。


HotSpot最適化にかかる時間


上記のベンチマークのように、比較的短い時間で終了するものは「マイクロ・ベンチマーク」と呼ばれます。しかし上述したとおり、HotSpot JVMでは最適化をはじめる前にインタプリタ・モードでコードを実行し、HotSpotの分析に時間を費やします。そのため、マイクロ・ベンチマークでは、HotSpot JVMによる最適化の効果をほとんど得ることができません。

HotSpot JVMにおいて、こうしたマイクロ・ベンチマークで十分なパフォーマンスを得るには、ベンチマーク部分をメソッドとして切り出し、それを繰り返し呼び出すようにコードを修正します。以下は、上述のベンチマークを修正した例です。

public class HotSpotBenchmark {
   public static void runTest() {
      int value=0;

      // Repeatedly executes feature to measure performance.
      for (int i=0; i<100000000; i++) {

         // Replace line with your favorite computation.
         value +=i;
      }
   }

   public static void main(String[] argv) {
      // Run benchmark multiple times. This will allow us to
      // see when HotSpot begins executing compiled code.

      for (int i = 0; i < 8; i++) {

      // Record the start time.
      long start= System.currentTimeMillis();

      // Run benchmark test.
      runTest();

      // Record the finish time.
      long finish= System.currentTimeMillis();

      // Now report how long test ran.
      System.out.print ("Time spent = " +
         Long.toString(finish - start) + " ms\n");

      }
   }
}

このプログラムをHotSpot JVMで実行すると、以下のような結果が得られます。

$ /opt/java1.3/bin/java HotSpotBenchmark
Time spent = 23372 ms
Time spent = 23400 ms
Time spent = 23372 ms
Time spent = 11 ms
Time spent = 11 ms
Time spent = 11 ms

ここで、ベンチマーク部分のメソッドはインタプリタ・モードのままで3回実行されていることに注目してください。一般には、HotSpot JVMが最適化を終えるまでには1〜2分を要します。その最適化の結果、HotSpot JVMではClassic JVMの80倍の高速化を達成していることが分かります。

パフォーマンス・チューニングを目的としてベンチマークを作成する際には、それがアプリケーション全体のアーキテクチャを反映できているかを見直してください。HotSpot JVMの効果を高めるには、そのベンチマークが十分に長時間実行され、「HotSpot」部分が繰り返し呼び出されなくてはならないのです。

連載記事一覧 戻る ページ:  戻る   |   1   2

連載 「Javaパフォーマンス・チューニング」記事一覧

第1回:基本的ルール、パフォーマンス・ツールの使い方
第2回:ガベージ・コレクション
第3回:ヒープ・メモリ管理
第4回:マルチスレッドによるリソース競合
第5回:メモリ・リークの発見
第6回:メモリ・リーク解析とHotSpot JVM

 その他の連載記事


本ページの内容は執筆時の情報に基づいており、異なる場合があります。

お問い合わせ

ご購入前のお問い合わせ


ご購入後のお問い合わせ

オンラインサポート
製品の標準保証でご利用いただける無償のサービスです。

ショールーム

ショールーム 導入をご検討のお客様へ
業務アプリケーションの継続・標準化・開発性とシステム担当者様、システム開発者様が抱える悩み・疑問に対する解決策実体験して頂けます。
印刷用画面へ
プライバシー ご利用条件・免責事項 ウェブマスターに連絡