Java デバッグツール NetBeans Profiler

最終更新日:2005/10/27

目次

>> NetBeans ProfilerによるTomcatのリモートプロファイリング

NetBeans Profilerについて

NetBeans ProfilerNetBeansにおけるプロファイリング機能を提供するツールです。共にSUNがスポンサーとして開発が続けられているプロダクトで、商用/非商用を問わず無償で利用できます。

動作環境に制限はあるものの、無償でありながら非常に便利な機能を持っており、また開発現場への導入が容易であるという特徴も持っています。

機能

以下の機能を持っています(http://profiler.netbeans.org/features.htmlより)。

この中でも特にCPUプロファイリング, メモリプロファイリング, メモリリークデバッグについて見ていきます。

動作環境

OS

2005/10現在の最新版である Milestone 9 では、以下のプラットフォーム用の媒体が提供されています。

JDK

以下のJDKがサポートされています。

残念ながらSUNの提供するJDK 1.4.2 はプロファイリング対象にできません。これは NetBeans4.1 向けの NetBeans Profiler Milestone 8 でも同様です。

インストール

NetBeansのインストール

NetBeans ProfilerはNetBeans上で動作するため、まずはNetBeansをインストールします。NetBeans Profilerのバージョンによって対応するNetBeansのバージョンが異なります。

NetBeans Profiler NetBeans
Milestone 9 5.0 beta
Milestone 8 4.1

今回は最新のMilestone 9を使う予定ですので、NetBeans 5.0 betaをインストールします。

netBeans.orgからNetBeansをダウンロードします。OSがWindowsならばnetbeans-5_0-beta-bin-windows.exeをダウンロードします。

後はインストーラの指示に従ってインストールして下さい。

NetBeans Profilerのインストール

NetBenas Profiler ProjectよりMileStone 9をダウンロードします(Windowsの場合は profiler-m9-win.exe)。インストールはインストーラの指示に従って下さい。

サンプルプロジェクト

新規プロジェクトの作成

プロファイリングを行う前に、プロファイリング対象となるサンプルプロジェクトをNetBeansに作成します。まずはNetBeansを起動し、

File>New Project>Category:General, Projects:Java Applicationと選択し、プロジェクトの名前と場所を入力してプロジェクトを作ります。このとき作成するプロジェクトをMainプロジェクトにするかどうかのチェックのある画面が表示されますが、このチェックはONにしておきます(デフォルトでONになっているはずです)。これで画面左に作ったプロジェクトが追加されます。

プロファイリング対象

今回プロファイリングの対象として、以下のようなプログラムを使うことにします。

クライアント-サーバシステムで通信はRMIで行います。サーバ側では複数のタスクを用意させ、クライアントからの指示に従ってタスクを実行するというものです。とりあえず用意したタスクは4つで、それぞれクラス名の通りの動作を行います。以下はこの4つのタスクを実行したときの jconsole のヒープメモリグラフの遷移の様子です。

図中の番号は以下の操作を実行したことを示しています。

  1. 定常状態においてGCを実行
  2. LightTaskを実行
  3. HeavyTaskを実行
  4. LargeMemoryTaskを実行
  5. GCを実行
  6. MemoryLeakTaskを実行
  7. GCを実行

ソースファイルのコピー

作成したプロジェクトのsrcフォルダへソースファイルをコピーすると、NetBeansが自動的にビルドを開始し、その一覧が表示されます。

ここで実行したいクラスを選択し、右クリックから「Run File」を選択するとそのクラスのmainが実行されます。緑色の矢印が付いているのがmain()を含む実行可能なクラスです。ですが、今回はプロファイリングを行うので、ここから実行はせず次に示す方法で起動します。

プロファイリング

前準備

プロファイラを初めて起動する場合は、まずCalibrationを行う必要があります。メニューからProfile>Advanced Commands>Run Profiler Calibrationを選択します。すると以下のようにJVMの選択画面が出てくるため、プロファイリングに使用するJVMを選択します。

Calibrationに成功すると以下の画面が表示されます。これでプロファイリングの前準備は完了です。

プロファイラの起動

プロファイル対象のプロジェクトを選択した状態で、メニューから Profile>Profile Main Projectを選択すると以下のダイアログが表示されます。

プロジェクトを初めてプロファイリングする場合はbuild.xmlを書き換える必要があるようで、書き換えてもよいかを聞いてきます。特に気にせずOKを選択してます。すると以下のようにmain()を含む実行可能なクラスの一覧が表示されるので、

プロファイリング対象にしたいクラスを選択してOKをクリックします。すると以下の画面が表示されます。

この画面でプロファイリングしたい項目を選択して画面下のRunをクリックすることでアプリケーションの実行とプロファイリングが開始されます。

アプリケーションのモニタリング

プロファイリングの項目で、「Monitor Application」を選択すると以下の画面に切り替わります。

画面中央はスレッドの活動の様子を示すグラフです。デフォルトではすべてのスレッド(終了したものも含む)が表示されていますが、現在生きているスレッドや終了したスレッドだけ表示させることも可能です。グラフのすぐ上のコンボボックスの値が"All Thread"になっていますが、この値を変えることで表示させるスレッドが変わります。

またあるスレッドの活動状況を詳細に見たい場合は、そのスレッドをダブルクリックします(下図)。

残念ながら各スレッドのスレッドダンプを表示させることはできないようです。デッドロックの検出に有効な手段ですが、これを行いたい場合は(Windowsならば)コンソールからCtrl + breakを送るか、またはjconsoleを使えば任意のスレッドのスレッドダンプを表示できるため、そちらを使うという方法もあります。

画面下の3つのグラフは左からそれぞれ、ヒープメモリ, GCメモリ, スレッド数を表すものです。それぞれダブルクリックすると画面中央へ拡大表示されます。

デフォルトでは現時点から少し前までの区間のデータを表示しますが、区間のズームイン、ズームアウトも可能です。上の例はアプリケーション起動時から現在までのヒープメモリ量の遷移の様子を表示したものです(グラフ左上の"Scale to Fit"を選択)。赤色がヒープサイズ、紫色が実際に使用しているヒープ量を示しています。これを見るとあるとき大量にヒープを消費し、それによってヒープサイズも拡張されたものの、その後のGCで使用しているヒープ量だけでなく、ヒープサイズそのものも縮小されていることがわかります。

パフォーマンス分析

パフォーマンス分析を行う場合は、先に出てきた画面で「Analyze Performance」または「Analyze Code Fragment Performance」を選択します。「Analyze Performance」ではアプリケーション全体、またはアプリケーションの一部(クラスやメソッド)に対するプロファイリングを行います。

ここでは「Analyze Performance」を選択し、アプリケーション全体のパフォーマンス分析を行うために、「Entire Application」を選択します。

また、JDKのコアライブラリやサードパーティのライブラリのパフォーマンス分析結果が必要ない場合は、それらを除外することができます。上の画面にあるように、デフォルトではJDKのコアライブラリをパフォーマンス分析対象から除外するフィルタが用意されています。フィルタをカスタマイズすることも可能で、その場合は「Customize Filter」ボタンをクリックし、カスタマイズを行います。今回はこのデフォルトのフィルタを使うことにします。

上の画面で「Run」ボタンをクリックするとアプリケーションが起動し、プロファイリングが開始されます。

「Run」ボタンクリックでプロファイリングが開始されますが、その状況を表示するには画面左の「Profiler」タブから「Live Results」を選択します(下図)。

そうすると画面右にパフォーマンス分析の様子がリアルタイムで表示されます。パフォーマンス分析を行うには、この状態で

  1. パフォーマンス収集データをリセットする
  2. 分析対象操作を実行する
  3. プロファイリング結果のスナップショットを取得する
  4. 取得したスナップショットを解析する

という流れになります。1のパフォーマンス収集結果のリセットは、上の図の「Live Results」の下にある「Reset Collected Results」を選択することで行われます。またスナップショットの取得は同じく「Take Snapshot」を選択することで行われます。以下はクライアントアプリケーションからHeavy Taskを実行させた後に取得したスナップショットです。

ひとつのスナップショットに対してタブが4つ生成されます。上の画面はその中の「Combined」を選択した状態です。2つのグラフのうち、上がメソッドのCall Tree, 下がメソッドのHot Spotを示しています。その名の通り、下のグラフからアプリケーションのHot Spotを発見できます。また上のグラフからはHot Spot呼び出しを含むCall Treeが表示されているので、Hot Spotをどこから呼び出しているかがわかります。

コードフラグメントのパフォーマンス分析

プログラムの特定の箇所に特化したプロファイリングを行う場合は、下の画面の「Analyze Code Fragment Performance」を選択します。

「Select Code Fragment」ボタンを選択して表示される画面で対象クラスとメソッドを選択し、さらに必要に応じてそのメソッドの何行目から何行目を対象にするか選択します。そうして実行すると、以下のように選択した部分の実行にかかった時間が表示されます。

表示されるのは選択範囲の実行にかかった時間だけですが、ピンポイントでパフォーマンス分析を行いたい場合に有効です。

メモリ分析

メモリ分析を行うには、下の画面で「Analyze Memory Usage」を選択します。

オブジェクト生成だけでなくGC情報も記録する場合は「Record both object creation and garbage collection」を選択します。特に理由がない限りこちらを選択することで良いでしょう。オブジェクト生成時のスタックトレースも記録させるために「Record Stack Tracefor Allocation」にもチェックを入れておきます。「Run」ボタンをクリックするとアプリケーションが起動し、プロファイリングが開始されます。パフォーマンス分析の場合と同じように、ここでも画面左の「Profiler」タブから「Live Results」を選択し、メモリ分析結果を表示させます。

メモリ分析では、各クラスのオブジェクトが占めるバイト数, 生存しているオブジェクト数, 生成されたオブジェクト数, 世代別GCに関する情報が表示されます。デフォルトではその時点でヒープを最も消費しているクラスが昇順で表示されます。

明示的にGCを起こさせたい場合は以下のゴミ箱のアイコンをクリックします。

NetBeans Profilerでメモリリークの分析を行うには、上の状態から

  1. メモリ収集データをリセットする(パフォーマンス分析と同じ操作)
  2. 分析対象操作を実行する
  3. プロファイリング結果のスナップショットを取得する(パフォーマンス分析と同じ操作)
  4. ヒープ量の多いクラスを選択し、右クリック>「Show Allocations Stack Trace」を選択する
  5. そのクラスのオブジェクトが生成された経路を特定し、メモリリークの原因を調査する

というような流れになります。以下はクライアントアプリケーションからすべてのタスクを一度だけ実行した状態で、int[]を選択して右クリックから「Show Allocation Stack Trace」を選択した結果です。

この結果を見ると、int[]オブジェクトを最も生成したのはjava.util.Calendarのコンストラクタであることがわかります。次のこのコンストラクタがどういう経路で呼び出されているか見るために、+アイコンをクリックしてスタックトレースを展開します(下図)。

Calendarクラスのインスタンスを生成している箇所を、スタックトレースを一つずつ遡っていきながら見ていくと、JDKのコアライブラリを除けばsample.server.MemoryLeakTask.execute()が見つかります。実際、このexecuteメソッドでは以下のコードがあり、メモリリークを引き起こしています(listはstaticなListオブジェクトで決して回収されない)。

 for (int i = 0; i < 10000; i++) {
     list.add(Calendar.getInstance());
 }

このようにある時点からある時点までの操作でヒープに残ったオブジェクトを容易に把握することができ、メモリリークの分析に非常に役立つツールだと思います。

リモートプロファイリング

これまでのプロファイリングではNetBeansに作成したプロジェクトを対象にしていましたが、NetBeansはリモートプロファイリングも可能です。プロファイリングに対する要求はさまざまで、例えば以下のようなケースがあると思います。

このような場合、リモートプロファイリングが有効です。

以降、以下のような構成でリモートプロファイリングを行うことを前提とします。

Remote Profiling Packsのインストール

NetBeans Profilerでリモートプロファイリングを行うためには、Remote Profiling Packsをダウンロードしてインストールする必要があります。

Remote Profiling Packsのダウンロード

Download The NetBeans ProfilerのAdditional DownloadsよりRemote Profiling Packsを選択し、プロファイリング対象のマシンのOSとJDKにマッチする媒体をダウンロードします(Windows + JDK5.0の場合は profiler-server-m9-windows-15.zip)。

Remote Profiling Packsの配置

ダウンロードした媒体をプロファイリング対象のマシンへ展開し、適当なディレクトリへ配置します。後にJavaコマンドラインパラメータとして追加することになるため、2バイト文字を含まないディレクトリへ配置しておくと良いでしょう。

Calibrationの実行

ダウンロードした媒体にcalibration.bat(Unixの場合はcalibration.sh)が含まれているので、それを実行します。これにより、batを実行したユーザのホームディレクトリに.npprofilerというフォルダが生成されます。

プロファイリング対象アプリケーションの起動

アプリケーション起動時にリモートプロファイリングのためのオプションを追加する必要があります。Windowsの場合は以下のようなコマンドになります(Remote Profiling PacksをCドライブ直下に展開した場合)。

java -agentpath:"c:\profiler-server-m9-windows-15\lib\deployed\jdk15\windows\profilerinterface.dll"=
"\"c:\profiler-server-m9-windows-15\lib\"",5140 クラス名

上のコマンドは実際は改行せず、1行目の最後の=の後にスペースは入れません。

リモートプロファイリングの実行

クライアント側でNetBeansを起動し、メニューからProfile>Attach Profilerを選択するとプロファイリングの種類を選択する画面が表示されます。その画面の一番上で選択するプロジェクトを、Global Attachに設定します。

もしプロファイリング対象のアプリケーションがNetBeansプロジェクトとして作られていれば、そのプロジェクトをインポートしてここで設定することにより、プロファイリング結果からソースコードエディタへの切り替えができるようになります。ですが、NetBeansプロジェクトの作成が面倒な場合は、このようにGlobal Attachを選択すればOKです。

次に画面左下の「Attach Wizard」を選択し、アタッチするアプリケーションの設定を行います。


プロファイリング対象アプリケーションの種類をまず設定します。この例ではプロファイリング対象はJavaアプリケーションなので、Applicationを選択します。

次はプロファイリングターゲットの設定です。


今回はリモートで動作するアプリケーションのプロファイリングを行うので Remoteを選択し、ホスト名とホストOSを設定します。設定が終わったらNextをクリックし、次に表示される画面でFinishボタンをクリックして設定を終了します。

プロファイリングタスク選択画面へ戻ったら、プロファイリングしたいタスクを選択し、画面下のAttachボタンをクリックすればリモートプロファイリングが開始されます。後は通常のプロファイリングと同じ操作になります。

まとめ

リモートプロファイリングについてまとめると、

JDK5.0_04が恐らく最大のネックだと思いますが、一時的にJDK5.0_04をインストールする方法もあると思います。JDKのバグに起因するものを除けば、アプリケーションの振る舞いやパフォーマンスはそれほど変わらないはずです。

また今回はJavaアプリケーションのリモートプロファイリングを行いましたが、Webアプリケーションのプロファイリングも可能です。Tomcatの場合はTomcatを起動させるバッチファイルに上記のオプションを追加すればよいでしょう。


資料室へ戻る


Copyright (c) 2005 OKI Software Co., Ltd.