Java開発の問題解決を助ける(2)
プロファイラでメモリリークとパフォーマンス問題を解決


メモリの無駄を作っている部分を特定する

 前ページでメモリを無駄遣いしているクラスを特定しました。ではもう少し具体的にどこで無駄遣いが起こっているかを調べてみましょう。プロファイル結果が表示されている画面にあるアイコン[ Take Snapshot of Collected Results] をクリックしてスナップショットを取得します。スナップショット画面ではそれぞれのクラスを右クリックし[Show Allocations Stack Traces]を選択することで、そのクラスがインスタンス化されたプログラム中の部分を取得することができます。

画面5 インスタンス生成のスタックトレース

 このスタックトレースのメソッドを右クリックし[Go To Source]を選べばソースコードにジャンプすることができ、そのままデバッグを行うことができます。このようにインスタンスが生成された個所から処理をたどったり、その個所を中心にデバッガのブレークポイント機能を使って処理を追跡することによってメモリリークを引き起こしている個所を切り分けることができます。

 今回のサンプルプログラムの場合、WordCounter.javaのコンストラクタの処理中で、使用されていないリスト「allWords」に生成されたインスタンスの参照が追加されていることによって、メモリリークが引き起こされていることが分かります。また、最もメモリを使用していたbyte[]もここで確保され、そのまま使用されていないことが分かります。

  12:    private static List allWords = new Vector();
13:    private byte[] buffer;
14:    
15:    /**
16:     * コンストラクタ.
17:     * @param word 単語.
18:     */
19:    public WordCount(String word){
20:        allWords.add(this);
21:        buffer = new byte[1000];
22:        this.word = word;
23:        count = 1;
24:    }

パフォーマンスボトルネックを探せ!

 次に、プロファイラを用いパフォーマンスのボトルネックを発見してみましょう。パフォーマンスが低下する原因はプログラムデザインの問題や、設定の問題、メモリ不足などさまざまなところにあります。それらさまざまな原因の中で一番大きな原因は「パフォーマンスについては後からチューニングすればよい」という考えです。一般にアプリケーションの開発が進めば進むほど、プログラムの修正は全体に大きな影響をもたらすために難しくなります。このため、開発が進むにつれてチューニングできる範囲も同時に限定され、チューニングの効果も出づらくなります。しかし、そのような状況の中でどうしても問題を解決しなければならないという状況も避けられない場合があります。そのような場合にいち早くパフォーマンスボトルネックの原因を探り、解決方法を提案できるよう作業の進め方やツールの使い方を学んでいきましょう。

どうしてパフォーマンスの問題はなかなか解決しないのか

 パフォーマンスが低下する原因は多種多様ですが、特に顕著な原因としては(1)ファイルやネットワークなどのI/O処理待ち、(2)マルチスレッド環境での同期待ち、(3)処理自体が非効率といった原因があります。パフォーマンスの問題がなかなか解決しない原因はプログラムのどこの部分でパフォーマンスの問題が生じているかがよく分からないという点にあります。プログラム中に各処理の処理時間をログに出力させることでプログラムのどの部分がパフォーマンスの問題を引き起こしているかを調べていくこともできますが、パフォーマンスの問題はプログラムの1カ所で起こっている場合と、プログラムのさまざまな部分で起こっている場合があり、1つのメソッドの処理を見直すだけでは問題が解決しないような場合ではログを追跡するだけではなかなか原因を特定することができないために問題個所の特定に時間がかかってしまいます。

パフォーマンスボトルネックを見つけるには


 パフォーマンスボトルネックの発生個所を見つけるには「合計処理時間の多いメソッド=(メソッド処理1回当たりの処理時間)×(メソッドの呼び出し回数)」を探すことが重要です。パフォーマンスボトルネックとなっているような処理は合計処理時間が多いものである場合がほとんどです。メソッド処理1回当たりの処理時間は次のコードのようにメソッド中に実行時間をログ出力するようなコードを記述することで比較的簡単に計測できますが、すべてのメソッドに記述することは大変で、ログ出力を見るのも根気の要る作業となります。

      long startTime = System.currentTimeInMillis();

    // 処理

    System.out.print("このメソッドの処理時間: ");
    System.out.print(System.currentTimeInMillis()- startTime);
    System.out.println("ミリ秒");

 メモリリークを探すために使用したプロファイラ・ツールはパフォーマンスボトルネックを見つけるためにも便利です。プロファイラ・ツールはメソッドごとの合計処理時間をプログラムに特別なコードを書かずに取得することができ、特に処理に時間がかかっている部分を簡単に見つけることができるように工夫されています。

2/3

 INDEX

第2回 Java開発の問題解決を助ける
  Page1
メモリリーク(メモリの無駄遣い)を探せ!
プロファイラを使ってみよう
  Page2
メモリの無駄を作っている部分を特定する
パフォーマンスボトルネックを探せ!
  Page3
プロファイラでパフォーマンスの問題を解決








Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間