連載
» 2007年07月25日 00時00分 公開

現場から学ぶWebアプリ開発のトラブルハック(5):OutOfMemoryエラー発生!? GCがあるのに、なぜ? (2/2)

[高橋和也,NTTデータ]
前のページへ 1|2       

OutOfMemoryErrorを防ぐためにはどうすればよいか?

 さて、簡単にトラブルの事例を見てきたが、皆さんの周りでもOutOfMemoryErrorに関するトラブルは見掛けるのではないだろうか。そのトラブルの原因はさまざまだが、JavaVMに対する設定やアプリケーションの不備によるものが多いかと思われる。

 そこで、今回はOutOfMemoryErrorを防ぐためのアプリケーションとJavaVMの設定に関するポイントを確認していく。

ポイント【1】JavaVMに対する設定の不備

 JavaVM動作時に利用されるメモリ領域のうちヒープ領域は、アプリケーション実行時に生成するオブジェクトが格納される。ヒープ領域はJavaVMごとに確保され、生成されたすべてのスレッドで共有されるメモリ領域である。

 このヒープ領域が不足した場合に発生するエラーがOutOfMemoryErrorである。

 ヒープ領域は、デフォルト設定では、環境にもよるが64MBytesなど非常に小さいため、Webアプリケーションを実行すると、メモリ不足に陥ってしまうだろう。その場合、JavaVMの起動オプションである-Xms-Xmxを利用して、ヒープ領域を十分に確保する必要がある。

編集部注:JavaVMの起動オプションについて詳しく知りたい読者は、Java Solution FAQの「javaコマンドを使いこなす」をご参照ください。

十分なヒープ領域を確保しているか?デフォルト設定のままではないか?

 どれくらいヒープ領域を確保すればよいのかは一概にはいえない。いくつかの設定でテストを実施し、最適な値を求めていくことになるが、一般的にアプリケーションの全実行時間に対するGCの全実行時間の割合が15%以下になるように調整していくのが望ましい。

ポイント【2】アプリケーションの不備、GCの働き

 前述のように、JavaVMの起動オプションにて十分なヒープ領域を確保しているにもかかわらず、OutOfMemoryErrorの発生やGCが頻発する場合、メモリリークの恐れがある。

 今回取り上げた事例のGCログ(図2)が典型的な例である。Javaアプリケーションでは、不要になったオブジェクトはGCの働きによってヒープ領域から削除されるので、メモリリークがなぜ起きるのか、読者の中には不思議に思う人もいるかもしれない。

 実はGCは、使わなくなったと判断したオブジェクトしかヒープ領域から削除しない。そのため、オブジェクトが不要と判断されなければ、GCによってヒープ領域から削除されないため、いつまでもオブジェクトが残ってしまうのだ。

 以上のことを踏まえて、開発を進めていくに当たって、気を付けるべき代表的なポイントを以下にまとめてみた。

static変数に巨大なオブジェクトを格納していないか?

 static変数はアプリケーションが終了するまで利用されると見なされるため、GCの対象外となる(ただし、自前のクラスローダを利用している場合は除く)。

 例えば、static宣言されたHashMapArrayListなどが存在し、それに格納されたオブジェクトが不要になっても後始末されていない場合、OutOfMemoryErrorを引き起こすといったことが考えられる。

 static宣言が本当に必要な変数であるかを確認し、static宣言が必要であれば、参照されるオブジェクトに不要なものが残らないように管理すべきであろう。

サーブレットコンテキストやセッションに巨大なオブジェクトを格納していないか?

 JavaによるWebアプリケーションでは、ServletContextやHttpSessionを利用していくが、これらもstatic変数と同等、もしくはそれより短いスコープではあるが、継続的に利用されていると見なされるオブジェクトである。

 WebアプリケーションでHttpSessionを利用してセッション管理をしている場合、セッションを確立している間は、メモリ上に存在し続ける。そのため、巨大なオブジェクトをHttpSessionに格納した場合、1人で利用している分には問題がなくても、同時に複数人で接続した場合は大量のメモリ領域を必要とする。

 例えば、DBから取得した膨大な件数の全件検索結果を、「次の処理でも使うかもしれない?」と思って、何となくそのままHttpSessionに格納していることはないだろうか。

 本当に格納する必要があるかを確認し、格納する必要があっても、最大検索結果件数が多い場合は小分けに検索するなどの工夫は必要であろう。

セッションタイムアウト時間は適切か?

 さらに、HttpSessionを利用している場合、セッションのタイムアウト時間が適切かどうかも確認しておく必要がある。タイムアウトすればセッションが無効化されるが、タイムアウトするまではセッションにデータが残ってしまうからだ。

セッションの無効化処理は行っているか?

 また、メモリを有効活用するためにも、ユーザーがログアウトする際には、HttpSessionのinvalidate()メソッドを利用したセッションの無効化処理の実行も有効である。

トラブルは教訓の母

 今回はOutOfMemoryErrorを発生させないためのアプリケーションとJavaVMの設定に関するポイントを紹介した。失敗は成功の母といわれるように、トラブルからはたくさんの教訓を得ることができる。

 もちろん、今回取り上げた事例以外にもメモリに関するトラブル事例は多数あるが、得られた教訓は開発の中で生かし、トラブルをなるべく早い段階で防げるように役立てていただければと思う。

プロフィール

NTTデータ
高橋 和也(たかはし かずや)

Web系システムでのJavaフレームワーク開発、業務アプリケーション開発と開発プロセスの策定、トラブルシューティングなどを経て、現在は、開発生産性を向上させるツール開発に従事するかたわらプロジェクトに対する主に設計・製造・試験に関する技術支援を担当している。
開発の理想論と現実論のバランスが取れた実現性のある開発ができればと思い、日々業務に従事している。



前のページへ 1|2       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。