Programming SHOT BARへようこそ。本日はVMの管理するメモリの話です。メモリリークによるOutOfMemoryの話ではありません。
VMが扱えるメモリの上限
一般的な32bitのJavaVMが管理できるメモリの上限は1.7G程度です。 JavaのVM自体はOSから見れば単一アプリケーションにすぎません。 Javaのアプリケーション内でのメモリ確保は、VMが確保したメモリが分配されているわけです。ですから、OS上からJavaVMが確保しているメモリを見てもVM内でどれだけのメモリが利用されているかはわかりません。
これはわりと嵌る人が多いように思います。少なくとも過去にBBSで2度以上見た覚えがあります。 Javaでもメモリ使用量を観測しようとした場合、WindowsのタスクマネージャでJavaVMが使用しているメモリを見てもあまり意味がありません。これはVMが確保しているメモリ総量よりは大きい値になりますが、確保した領域中、どれだけが空きメモリなのかはわからないのです。それはOSの知るところではなく、JavaVMの管理下にある情報なのです。 JavaVM内での空きメモリは java.lang.Runtime#freeMemory()で参照できます。またjconsole によって外から接続してメモリ使用状況を確認することも出来ます。
JavaVMが確保するメモリの上限は実行時のオプションで設定できます。 javaコマンドのリファレンスで説明されていますが、オプション-Xmxで上限設定をすることができます。しかし、上限はVMの実装によるため、ここでは設定できる上限値についての情報は記述されていません。 VMの実装によっては2Gを超えるヒープ領域が扱える"Large Heap"と呼ばれる機能を備えているものもあるようです。
Javaアプリケーションの稼動するサーバを構築した場合、 JavaVM自体はVMの本体も含め2G程度のメモリしか消費しません。それを超える物理メモリを乗せていても活用できない場合があります。サーバサイドで動かすのであれば64bit版のVMを使いたいところです。
たとえ64bit版を使っていたとしても物理メモリを超える容量を設定してはいけません。 OSが仮想メモリをサポートしているでしょうから止まるということは無いにしても、深刻なパフォーマンスの劣化をもたらす場合があります。
VMは該当オブジェクトが配されているメモリがスワップされた領域なのか、そうでないのかを管理するわけではありませんから、多量のスワップが発生することがあります。
そのような事情から、Javaのアプリケーションで使用できるメモリの上限はおのずと制限されます。
上限を振り切る可能性
サーバサイドでの処理は時にヘビィで、瞬間的に大量のメモリを消耗することがあります。 Excelファイルを生成するApache POIなどはその典型で、非常に多くのメモリを消耗します。サーバサイドでは並列にユーザからリクエストを受けるのが通常ですから、このメモリを食う処理が多重に動いた場合、メモリ上限を超え、OutOfMemoryとなることがあります。
これはメモリリークではないため、抜本的な対応は難しいのですが、VM内で片付けるなら Worker Threadパターン( 増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編の8章参照)を利用します。作業用のThread本数を制限し、同時に多量に並列起動しないようにするわけです。 JavaSE5.0以降であればjava.util.concurrent.ThreadPoolExecutorを使うことで比較的容易に対応できます。
しかし、いずれにせよデータ量で使用メモリが変動しますから、正確な上限がつかめるわけではありません。いっそ、POIによるExcel生成を別VMに分けてしまって、VM間で受け渡しするようなシステム構成を考えたほうがよいのではないでしょうか。
投稿日時 : 2007年9月20日 16:26