メモリの最適化について - Java SE Embedded 8

JavaはOSから見ると、1つのプロセスとして動作しますが、内部的には大きく分けて以下のような3つのメモリ領域が存在します。

HEAP: Javaアプリがインスタンスを生成すると、この領域にメモリが確保されます。

NON-HEAP: NON-HEAP領域は、JVMが実行の最適化のために使用する領域で、Code CacheとMetaspaceという2つの領域に分かれています。

Code Cache: 実行中にJITコンパイラにより変換されたマシン語を保持するための領域
Metaspace: HEAPにロードされたクラスに関するメタ情報等を保持する領域  

JavaVM内部で使用される領域: VMが実行時に内部的に使用する領域です。


メモリの構成と測定方法について

次に、メモリが実際にどのぐらい使われているかを計測する方法についてです。以下はそれぞれの領域と、メモリの状況を見る方法について表した図となります。



HEAPはJava Mission Controlを使って画面から確認することもできますし (下図参照)、 あるいはJava SE標準で提供されている下記のAPIをアプリから呼び出すことで実際の使用量を取得することが可能となっています。 Mission Controlを使うか、APIをご使用になるかは状況次第で使い分けていただければと思います。さてAPIですが、以下のようになります。

HEAPの最大値を取得できます。 VMの起動オプション"-Xmx"で指定した値の近似値となります。
java.lang.Runtime.maxMemory();

利用可能なHEAPの総量を示します。 基本的にはVMの起動オプション"-Xms"で 指定した値の近似値となり、 "-Xms"がない場合は、"-Xmx"の近似値となります。
java.lang.Runtime.totalMemory();

測定時点での使用可能なHEAPサイズの概算値を返します。
java.lang.Runtime.freeMemory();

またNON-HEAPの状況を見る場合ですが、 APIによる計測方法はなく、 Java Mission Controlを利用して行います。 以下は参考となりますが、Java Mission Controlの該当する画面をキャプチャしたものとなります。 タイプが"NON_HEAP"となっている箇所がNON-HEAPとなります。

最後に、 HEAPでもなくNON-HEAPでもない領域についてですが、 Java VM内部で使用する領域ということもあり、この部分だけを解析するツールは存在しません。 強いてやるとするならば、プロセス全体が使っているメモリの量を計測し、 そこからHEAP/NON-HEAPのサイズを差し引く。というやり方になるかと思います。 OSにより様々かとおもいますが、 Linuxを例にとると、procfsでJavaプロセスが使用中の全物理メモリのサイズ (VmHWM or VmRSS) を計測し、 そこからHEAP/NON-HEAPを引くことで概算値を取得することができるかと思います。


使用メモリを調節するためのオプション

さて、実際にJVMのメモリの使用量を調節するにあたり、 まずは大前提として実行環境に最適なJVMが選択されていることを確認してください。 最適なJVMというのは、

  1. 組み込みデバイス向けには、 Embedded版のJVMが使われていること。 特にEmbedded向けのOracle JVMは組み込み用CPUに内部の処理が最適化されていたり、無駄なクラスをロードしないよう配慮されています。 なので、同じCPUアーキテクチャでも組み込みとそれ以外の環境によって適切な選択を行ってください。
  2. Minimal/Client/Server版のJVMが適切に使い分けられていること。 これらはJVMの起動オプションによって選択可能です。(参考URL: http://docs.oracle.com/javase/8/embedded/develop-apps-platforms/embedded-jvms.htm#CHDCHECF
  3. 必要最小限のCompactプロファイルが選択されていること。(参考URL: http://docs.oracle.com/javase/8/embedded/develop-apps-platforms/compact-profiles.htm#CHDGIIGE

またJVMの起動オプションの内、 メモリに影響を与えるものを以下に示します。

  • -Xms: ヒープサイズの初期値。 初期値を指定すると、 メモリ確保をコミットしようとする傾向から、使用している物理メモリの値が若干高くなる可能性があります。
  • -Xmx: ヒープサイズの最大値。
  • -XX:ReservedCodeCacheSize: Code Cacheのサイズ指定。 注) JITオプションを使わない場合でもCode Cacheの領域が使用されるため、0にはできません。
  • -Xint: JITオプションを無効とし、 インタプリタで動作します。 JIT使用時に比べメモリの使用量が減りそうですが、 意外とメモリサイズは変わりません。
  • -Xss: スレッド毎のスタックサイズを指定します。 スタックサイズの総数はスレッド数にも依存するため、 スレッド数が大きい場合はメモリの低減効果が大きくなります。
  • -XX:CompileThreshold: JITコンパイラは同じコードが指定回数以上呼び出されると動作し始めますが、 その時の呼び出し回数のしきい値を設定します。 指定した値が大きくなれば、 コンパイルされる可能性が下がるため、 Code Cacheの使用量が減るため、NON-HEAP領域のサイズが減る可能性があります。

上記のオプションは、 アプリを動作させるための要件にも依るため、 一概にどれを使えば良いかを言うのは難しいのですが、 パフォーマンスとメモリのバランスを取りながら、 少しずつパラメータの調整を行ってください。


Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

日本オラクルのエンベデッドJavaチームから、最新情報をお送りしていきます。

Search

Archives
« 9月 2015
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today