まずJVMとは、Javaプログラムを実行するための稼働環境であり、JVMはOSに依存した動きをします。各プラットフォームに応じたJVMが存在しており、このJVMがプラットフォームの違いを吸収しているため、Javaアプリケーションはプラットフォーム非依存を実現できます。
C言語では確保したメモリの開放もプログラマが行わなくてはなりませんでしたが、Javaではメモリ領域の開放をJVMがガベージコレクション(GC)と言う機能で担当してくれるため、プログラマはメモリに関して意識せずにコーディングを行えるようになります。
ガベージコレクション(garbage collection; GC)とは、JVMが動的に確保したメモリ領域のうち、不要になった領域を自動的に解放する機能です。ガベージコレクションは、JVMが新たにオブジェクトのインスタンスをJavaHeap領域(後述)に展開しようとした際に、必要量の領域を確保できなかったり、または連続した領域が確保できなかった場合に起動します。
ガベージコレクションは以下のフェーズで実行されます。
アロケーションの失敗(GC起動前)
オブジェクトをメモリ上に展開しようとしたが領域が確保できなかったため Allocation failureが発生。
Mark Phase
Mark Phaseでは使用されているオブジェクトを走査します。
Sweep Phase
Sweep Phaseではどこからも参照されていない未使用オブジェクトを削除します。
Compaction Phase
Compaction PhaseではHeap領域の使用中である領域をまとめてメモリのフラグメンテーションを低下させます。このフェーズはGCの中で最も負荷がかかるため、Sweep Phaseのみで十分領域が確保でき、フラグメンテーションも低い場合はこのフェーズを行いません。
GC起動後
オプションにより Mark Phaseはアプリケーション・スレッドが動作中でも実行することが出来ますが、その他のフェーズでは、このガベージコレクションが動作している時は全てのアプリケーション・スレッドは停止状態となります。
ヒープ(Heap)領域とは動的に確保可能なメモリの領域の事です。以下のようにシステム全体で使用する共通域、その他アプリケーションから使用される共通域、JVMがオブジェクト等を配置するための JavaHeap等に分けられています。
当然実行時に大量のオブジェクトを使用する場合は JavaHeapをたくさん使うことになりますし、アプリケーションにより必要とされるヒープ領域は異なってきます。しかし JavaHeapを大きく取り過ぎると NativeHeapの逼迫や、前述したガベージコレクション(GC)に時間が掛かってしまったりします。その他の要因を精緻化し適切なヒープサイズを設定することで OutOfMemoryや GCによる性能劣化を回避します。
JavaHeap
JavaHeap領域とは、PC上のメモリのような役割を持っており、JVMの作業用領域として使用されます。JVM 毎に一つずつ割り当てられ、JVM上で動作する全てのスレッドから共有されます。JavaHeapにはクラスやインスタンス化されたオブジェクトが格納されます。この領域はガベージコレクションの対象エリアであり、この領域にオブジェクトを格納しようとして領域を確保できない場合(verbose:gcの出力では Allocation Failure が出力されます)ガベージコレクションが行われ、領域が整理してオブジェクトを格納できるようにします。
ガベージコレクションを行っても領域が確保できなかったり、なんらかの理由で確保失敗した場合 stdout または stderr に java.lang.OutOfMemoryError がスローされます。
このサイズを設定するには Javaのコマンドラインオプションで、最大値「
-Xmx」、最小値「
-Xms」を設定します。
[ JavaHeapの最大を 512Mに設定]
java -Xms512m
NativeHeap
NativeHeapは JVM が自身の内部操作で使用するメモリで、生成されたコードや作成されたスレッドの数、GC中に Java オブジェクト情報の保存に使用されるメモリの量、コード生成中や最適化中に一時的に使用される領域の大きさなどによって異なります。
また、この領域には JNIネイティブコードや、JITコンパイルされたコード、ネイティブ JDBC ドライバ(JDBC Type2)の作業領域が割り当てられます。
stdout または stderr に Malloc エラー等の メモリを取得できなかったというメッセージが表示された場合は NativeHeapの領域を確保できていません。