OutOfMemoryエラー発生!? GCがあるのに、なぜ?:現場から学ぶWebアプリ開発のトラブルハック(5)(2/2 ページ)
本連載は、現場でのエンジニアの経験から得られた、APサーバをベースとしたWebアプリ開発における注意点やノウハウについて解説するハック集である。現在起きているトラブルの解決や、今後の開発の参考として大いに活用していただきたい。(編集部)
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宣言されたHashMapやArrayListなどが存在し、それに格納されたオブジェクトが不要になっても後始末されていない場合、OutOfMemoryErrorを引き起こすといったことが考えられる。
static宣言が本当に必要な変数であるかを確認し、static宣言が必要であれば、参照されるオブジェクトに不要なものが残らないように管理すべきであろう。
■サーブレットコンテキストやセッションに巨大なオブジェクトを格納していないか?
JavaによるWebアプリケーションでは、ServletContextやHttpSessionを利用していくが、これらもstatic変数と同等、もしくはそれより短いスコープではあるが、継続的に利用されていると見なされるオブジェクトである。
WebアプリケーションでHttpSessionを利用してセッション管理をしている場合、セッションを確立している間は、メモリ上に存在し続ける。そのため、巨大なオブジェクトをHttpSessionに格納した場合、1人で利用している分には問題がなくても、同時に複数人で接続した場合は大量のメモリ領域を必要とする。
例えば、DBから取得した膨大な件数の全件検索結果を、「次の処理でも使うかもしれない?」と思って、何となくそのままHttpSessionに格納していることはないだろうか。
本当に格納する必要があるかを確認し、格納する必要があっても、最大検索結果件数が多い場合は小分けに検索するなどの工夫は必要であろう。
■セッションタイムアウト時間は適切か?
さらに、HttpSessionを利用している場合、セッションのタイムアウト時間が適切かどうかも確認しておく必要がある。タイムアウトすればセッションが無効化されるが、タイムアウトするまではセッションにデータが残ってしまうからだ。
■セッションの無効化処理は行っているか?
また、メモリを有効活用するためにも、ユーザーがログアウトする際には、HttpSessionのinvalidate()メソッドを利用したセッションの無効化処理の実行も有効である。
トラブルは教訓の母
今回はOutOfMemoryErrorを発生させないためのアプリケーションとJavaVMの設定に関するポイントを紹介した。失敗は成功の母といわれるように、トラブルからはたくさんの教訓を得ることができる。
もちろん、今回取り上げた事例以外にもメモリに関するトラブル事例は多数あるが、得られた教訓は開発の中で生かし、トラブルをなるべく早い段階で防げるように役立てていただければと思う。
プロフィール
NTTデータ
高橋 和也(たかはし かずや)
Web系システムでのJavaフレームワーク開発、業務アプリケーション開発と開発プロセスの策定、トラブルシューティングなどを経て、現在は、開発生産性を向上させるツール開発に従事するかたわらプロジェクトに対する主に設計・製造・試験に関する技術支援を担当している。
開発の理想論と現実論のバランスが取れた実現性のある開発ができればと思い、日々業務に従事している。
- 数百キロのコードでブルー - ドクターTomcat緊急救命
- DB操作の“壁”を壊すJPAが起こした「赤壁の戦い」
- アプリ開発でも、よ〜く考えよう。キャッシュは大事だよ
- スレッドダンプの森で覚えた死のロックへの違和感
- ThreadとHashMapに潜む無限回廊は実に面白い?
- JavaのGC頻度に惑わされた年末年始の苦いメモリ
- 肥え続けるTomcatと胃を痛めるトラブルハッカー
- 【トラブル大捜査線】失われたコネクションを追え!
- 【真夏の夜のミステリー】Tomcatを殺したのは誰だ?
- OutOfMemoryエラー発生!? GCがあるのに、なぜ?
- DBアクセスのトラブルは終盤で発覚しがち……
- 【実録ドキュメント】そのログ本当に必要ですか?
- “Stop the World”を防ぐコンカレントGCとは?
- Webアプリの問題点を「見える化」する7つ道具
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- メモリは足りているのに“OutOfMemory”のなぞ
[連載]事例に学ぶWebシステム開発のワンポイント(9) メモリが足りているのに、OutOfMemoryのエラーに悩まされるケースは多い。いくつかの原因とその解決法を紹介 - JSPのスコープをちゃんと使いこなせてますか?
やり直し「JSPとTomcat」(9) JSP内のBeanオブジェクトの有効範囲(スコープ)はいろいろあるので、使うには少しコツが必要です。もう1度復習してみましょう - HotSpot VMの基本構造を理解する
チューニングのためのJava VM講座(前編) パフォーマンスチューニングに関わるエンジニアのためのJava VM講座。2回に渡ってHotSpot VMの基礎知識を解説します - ガベージコレクタの仕組みを理解する
チューニングのためのJava VM講座(後編) メモリ管理作業をプログラマに代わって行うガベージコレクションを理解することは、Javaのパフォーマンス確保に非常に重要だ