Java開発を行っているとOutOfMemoryErrorが発生し、ヒープサイズの拡張が必要になることが少なくありません。
本記事では、Javaのヒープサイズについての基礎知識から実際の設定方法についてご紹介していきます。
Javaのヒープサイズとは
Javaでは、プログラム実行時に生成されるオブジェクトのためのメモリ領域を「ヒープ領域」と呼び、その領域の大きさを「ヒープサイズ」と呼んでいます。
ヒープ領域の概要
JavaはJava Virtual Machine(JVM)と呼ばれる仮想マシン上で実行されますが、JVM上でプログラムが利用するメモリ領域として割り当てたものをヒープ領域と呼んでいます。
ヒープ領域は「New」と「Old」に分けられ、新たに作成されたオブジェクトや短期間だけ確保されるオブジェクト領域が「New」、寿命の長いオブジェクトが「Old」に該当します。
ヒープサイズの概要
ヒープサイズというのは、ヒープ領域の大きさで、「初期サイズ(-Xms)」と「最大サイズ(-Xmx)」を設定することが可能です。
ヒープサイズを大きくすることで、ガベージコレクションの回数を減らすことが出来るためパフォーマンスの向上に有効ですが、ヒープサイズを大きく設定しすぎるとリソースを無駄に消費したりする原因にもなってしまいます。
ヒープサイズとガベージコレクション
Javaでは、ガベージコレクションにより自動的にメモリ管理を行っているというのは知っている方も多いかと思いますが、このガベージコレクションが実行されるタイミングとしてヒープ領域がいっぱいになったタイミングがあげられます。
ヒープサイズを減らしているとすぐにヒープ領域がいっぱいになってしまい、ガベージコレクションの回数が増えてしまったり、メモリ不足でプログラムが強制終了してしまうことにも繋がるため、ヒープサイズの拡張を検討する必要が出てきます。
Javaのヒープサイズを確認してみよう
Javaのヒープサイズを確認する方法は複数存在しますが、今回はJava APIのRuntimeから取得する方法とコマンドからの起動オプションで取得する方法をご紹介していきます。
Javaプログラムで取得
Javaプログラムではサンプルのような記述でヒープサイズを取得することが出来ます。
public class Main { public static void main(String[] args) { long total = Runtime.getRuntime().totalMemory(); long free = Runtime.getRuntime().freeMemory(); long max = Runtime.getRuntime().maxMemory(); System.out.println("total: " + total); System.out.println("free: " + free); System.out.println("max: " + max); } }
実行した結果が下記です。
total: 136314880 free: 134346640 max: 2147483648
「totalMemory」で取得出来るのが「-Xms」で割り当てる初期サイズのヒープサイズを意味し、「freeMemory」はtotalMemoryから現在の使用領域を引いたサイズが表示されます。
つまりtotalMemoryからfreeMemoryを引いた値が、現在使用しているヒープサイズです。
また「maxMemory」では「-Xmx」にあたる最大サイズのヒープサイズが表示されます。
コマンドオプションで取得
次にjavaのコマンドオプションでヒープサイズを確認してみましょう。
$ java -XX:+PrintFlagsFinal -version | grep HeapSize 一部抜粋 size_t InitialHeapSize = 134217728 {product} {ergonomic} size_t MaxHeapSize = 2147483648 {product} {ergonomic} size_t MinHeapSize = 8388608 省略
Runtimeで取得した際と微妙に差はありますが、ほとんど同じ値が表示されていることを確認出来ます。
Javaの実行時にヒープサイズを指定する
Javaプログラム実行時にヒープサイズを指定する方法についても確認しておきたいましょう。
今回はコマンドから実行する方法とEclipse上で設定する方法についてご紹介していきます。
コマンド
コマンドからJavaプログラムを実行する場合、下記の形式でコマンドを実行します。
java -Xmsサイズ -Xmxサイズ クラス名
例えば「Sample1.java」クラスをメインとして、初期サイズ2MBの最大サイズ3MBで実行したい場合は下記の記述となります。
java -Xms2m -Xmx3m Sample1.java
Eclipse
Eclipseでの設定方法についても確認しておきましょう。
プロジェクトを右クリックして「実行」→「実行の構成」を選択します。
「Javaプロジェクト」から設定したいプロジェクトになっているかを確認します。
「引数」タブを選択し、「VM引数」のテキストエリアに「-Xms2m -Xmx3m」のように任意のヒープサイズを設定します。
テスト用サンプルコード
ヒープサイズの変化が分かるようにサンプルコードを用意しました。
public class Main { public static void main(String[] args) { StringBuilder sb = new StringBuilder(); int cnt = 0; while (true) { sb.append("10000000"); cnt = cnt + 1; System.out.println(cnt + "回目のループ処理です。"); } } }
実行してみると筆者の環境では「-Xms2m -Xms3m」の設定で「36863回目」まで、「-Xms2m -Xms10m」の設定で「294911回目」まで処理が継続されるような差が生まれました。
さいごに: ヒープサイズを調整してJavaプログラムを実行しよう
本記事では、Javaにおけるヒープサイズの概要と実際に確認および設定する方法についてご紹介してきました。
ヒープサイズは少な過ぎず多過ぎずに調整するのが難しい部分でもありますが、アプリのパフォーマンスを最適化する上でも重要な役割を担います。
調整方法をきっちりと把握した上で、プログラムに最適なヒープサイズとなるようしっかりと調整を行いましょう。
ヒープサイズをKBで求めたい場合は「/1024」、MBで求めたい場合は「/(1024 * 1024)」で取得出来ます。