Java開発の問題解決を助ける(2)
プロファイラでメモリリークとパフォーマンス問題を解決
サン・マイクロシステムズ
岡崎 隆之
2005/8/10
この連載は、Java開発を妨げるさまざまな問題の解決方法を扱います。前回はプログラムのバグを効率よく発見し解決する方法を紹介しました。第2回は、プロファイラを使ってメモリリークやパフォーマンスの問題を解決する手法を紹介します。
メモリリーク(メモリの無駄遣い)を探せ! |
メモリリークとは不要になったオブジェクトが何らかの理由で解放されず、メモリ領域を無駄に占拠してしまっている状況です。このような不要なオブジェクトが積もり積もっていくと、メモリ不足でシステムが停止してしまうなどの深刻な問題を引き起こす場合があります。ではこのような深刻な問題を引き起こしてしまうメモリリークの見つけ方、解決方法を学んでいきましょう。
■どうしてメモリリークは起こるのか
では、そもそもどうしてメモリリークが起こってしまうのでしょうか。Java仮想マシンは不要になったオブジェクトはガーベジコレクション処理によって自動的に解放します。ガーベジコレクション処理はオブジェクトが不要になったかそうでないかを、誰からも参照されていないことを判断基準にオブジェクトを開放していきます。この処理はほとんどの場合うまく動作するのですが、「ビジネスロジックから見て不要になったにもかかわらず参照が残っている」場合にはJava仮想マシンはその参照先のオブジェクトが不要になったことを判断できずメモリを開放することができません。これにより、メモリリークが発生してしまうのです。
■メモリリークを見つけるには
メモリリークが発生しているかどうかは、不要なオブジェクトがガーベジコレクション処理でメモリ上から開放されているかどうかを確認することで判断します。何回かガーベジコレクション処理が実行されているにもかかわらず開放されていないオブジェクトはどこかからか参照されている可能性が高く、メモリを無駄遣いしているオブジェクトの可能性があります。
最終的にそのオブジェクトがメモリを無駄遣いしているかどうかを判断するには、そのビジネスロジックの処理内容から判断する必要がありますが、オブジェクトの種類やそのオブジェクトを生成したコードを絞り込むことでメモリリークを起こしているコードを効率よく見つけることができます。
プロファイラを使ってみよう |
メモリリークの原因の絞り込みを効率的に行うためにはプロファイラ・ツールを用います。プロファイラ・ツールはメモリ中に確保されているオブジェクトのサイズや個数、オブジェクトが生成された場所といった情報や、メソッドの実行時間などを統計的な情報として取得することができるツールです。では、実際にサンプルプログラムを例にしてこのプロファイラ・ツールを使った問題の切り分けを行ってみましょう。 サンプルプログラムのコードはここ(sample.zip)からダウンロードできます。今回は無償で利用でき、Windows、LinuxやSolarisに対応したプロファイラである「NetBeans Profiler(http://profiler.netbeans.org/)」を使用します。
■メモリリークを含んだサンプルプログラム
サンプルプログラムは実行されているディレクトリ中のテキストファイルを再帰的に読み込んで、テキストファイル中に含まれる空白や改行で区切られた単語の数を数えます。例えば以下のようなファイルを読み込みます。
読み込むファイルの例(JDK 1.5に含まれるXusage.txtより抜粋)
|
このファイルの-Xmixedやmixed、modeといった空白で区切られた部分が単語としてカウントされます。実行すると、以下のように結果が表示されます。
|
では、このサンプルプログラムの問題点をプロファイラを使って検証してみましょう。
■開発環境とプロファイラの準備
まず開発環境とプロファイラをインストールします。
- 統合開発環境であるNetBeans 4.1をダウンロードページ(http://www.netbeans.org/downloads/index.html)からダウンロードし、インストールしてください。
- 次にプロファイラをダウンロードします。NetBeans Profilerのダウンロードページ(http://profiler.netbeans.org/download.html)から、それぞれのプラットフォームに合ったNetBeans
Profilerのインストーラをダウンロードしてください。ダウンロードページにはAdditional DownloadとしてJ2EEサーバに対するJDKなどが紹介されていますが、今回は使用しません。
- ダウンロードしたNetBeans Profilerのインストーラを実行します。NetBeans Profilerのインストーラは途中でNetBeansのインストールされているディレクトリを聞いてくるので、そのディレクトリを選択してインストールを続行します(例えばWindowsでNetBeans 4.1を標準インストールした場合は「C:\Program Files\netbeans-4.1」を選択します)。
画面1 インストール済みNetBeansの選択 |
次に、サンプルプログラムを実行できるようにプロジェクトを作成します。
- サンプルプログラム(sample.zip)を適当なディレクトリに展開します。
- NetBeansを起動し、メニューの[File]から[New Project]を選びます。
- プロジェクトのカテゴリ[General]にある[Java Project with Existing Sources]を選択し、次に進みます。
- プロジェクト名を入力して次に進みます。
- [Source Package Folders]にある[Add Folder]をクリックし、サンプルプログラムを展開したディレクトリを選び、[Finish]を押します。これでプロジェクトの作成が完了します。
画面2 プロジェクトの作成を終えたところ |
これでサンプルプログラムの実行準備が整いました。
■まずは現象を把握する
メニューの[Profile]から[Profile
Main Project]を選ぶとプロファイル対象のメインクラスを選択するように指示されるので、ここではWordCounterクラスを選択します。次に、プロファイリングタスクを選択する画面が出てきますが、今回はメモリについてのプロファイルを行うので[Analyze
Memory Usage]をクリックします。メモリリークを探す場合にはガーベジコレクションの情報が非常に重要な情報となるので、この情報を取得するために[Record
both object creation and garbage collection]を選択します。さらに[Record Stack
Trace for Allocations]にチェックを入れ、プログラム中のどこでオブジェクトが生成されたかを記録するようにします。
画面3 プロファイリングタスクの選択で選択後の画面 |
プロファイル結果はメニューの[Window]にある[Profiling]メニューの[Live Results]を選択することで取得することができます。
画面4 プロファイル結果 |
このプロファイル結果を見る際、最も重要な項目は右端のGenerationsの項目です。Generationsは何世代(ガーベジコレクション処理が1回起こるたびにオブジェクトの世代が1つ上がる)生き残ったかを示す値で、この数値が増加傾向にあるクラスはメモリリークの可能性が非常に高いと考えられます。メモリを無駄遣いしている可能性が高いクラスはbyte[]、String、char[]、WordCountといったクラスであることが推測できます。
1/3 |
INDEX |
||
第2回 Java開発の問題解決を助ける | ||
Page1 メモリリーク(メモリの無駄遣い)を探せ! プロファイラを使ってみよう |
||
Page2 メモリの無駄を作っている部分を特定する パフォーマンスボトルネックを探せ! |
||
Page3 プロファイラでパフォーマンスの問題を解決 |
- 実運用の障害対応時間比較に見る、ログ管理基盤の効果 (2017/5/9)
ログ基盤の構築方法や利用方法、実際の案件で使ったときの事例などを紹介する連載。今回は、実案件を事例とし、ログ管理基盤の有用性を、障害対応時間比較も交えて紹介 - Chatwork、LINE、Netflixが進めるリアクティブシステムとは何か (2017/4/27)
「リアクティブ」に関連する幾つかの用語について解説し、リアクティブシステムを実現するためのライブラリを紹介します - Fluentd+Elasticsearch+Kibanaで作るログ基盤の概要と構築方法 (2017/4/6)
ログ基盤を実現するFluentd+Elasticsearch+Kibanaについて、構築方法や利用方法、実際の案件で使ったときの事例などを紹介する連載。初回は、ログ基盤の構築、利用方法について - プログラミングとビルド、Androidアプリ開発、Javaの基礎知識 (2017/4/3)
初心者が、Java言語を使ったAndroidのスマホアプリ開発を通じてプログラミングとは何かを学ぶ連載。初回は、プログラミングとビルド、Androidアプリ開発、Javaに関する基礎知識を解説する。
|
|