2017-05-31 29 views
2

私のJavaプログラムは、メモリが指定された量に制限されている環境で実行する必要があります。 Javaサービスを実行すると、起動時にメモリが不足します。これは私が設定しています私が使用しているコマンドと値の一例であるulimitをjavaで正しく使用するには?

:理論的には

ulimit -Sv 1500000 
java \ 
    -Xmx1000m -Xms1000m \ 
    -XX:MaxMetaspaceSize=500m \ 
    -XX:CompressedClassSpaceSize=500m \ 
    -XX:+ExitOnOutOfMemoryError \ 
    MyClass 

を、私は上のドキュメントを見つけることができるすべてを占めてきました。ヒープ(1000m)とメタスペース(500m)があります。しかし、JVMの初期化時にメモリ不足になります。これは、約600mibをヒープ+メタスペースよりも大きく設定するまで発生します。

私がulimitを適切に設定できるように、どのような種類のメモリがありますか?

使用例:メモリが制限されたDockerコンテナでタスクを実行しています。これは、Linuxのcgroupが制限を行っていることを意味します。メモリの制限を超えると、cgroupはその制限を超えるプロセスを一時停止または強制終了することができます。私は実際に何かがうまくいかず、それがラップするbashスクリプトがタスクのイニシエータにエラーを報告できるように、あまりにも多くのメモリを使用する場合、Javaプロセスが正常に失敗するようにします。

私たちはjava 8を使用しているので、permgenの代わりにmetaspaceについて心配する必要があります。

更新:OutOfMemoryErrorで死ぬことはありません。これはエラーです:

Error occurred during initialization of VM 
Could not allocate metaspace: 524288000 bytes 
+0

メモリが足りなくなり、 'cgroups'によって殺されるか、メモリが足りなくなり、' OutOfMemoryError'がスローされますか? – EJP

+0

Javaは 'OutOfMemoryError'で終了します。私は質問を更新しました。 – tombrown52

+0

それはあなたがしたいことをやっている。 'cgroups'の制限内で実行可能なJavaメモリ引数を見つけるだけでいいです。それがなければ、あなたはそれをすることができません。 – EJP

答えて

1

実際には、ulimit javaは本当に難しいです。多くのプールは無制限であり、割り振りの試行が失敗するとJVMは致命的に失敗します。すべてのメモリが実際にコミットされているわけではありませんが、その多くは予約されており、ulimitによって課せられた仮想メモリの上限に向かってカウントされます。

多くの調査の後、私はメモリJavaの用途のさまざまなカテゴリの多くを明らかにしました。この答えは、64ビットシステム上でのOpenJDKとOracle 8.xのに適用されます。

ヒープ

これは、JVMのメモリの最もよく理解さの部分です。プログラムメモリの大部分が使用されます。 -Xmx-Xmsオプションで制御できます。

メタスペース

これは、ロードされたクラスに関するメタデータを保持するために表示されます。私は、このカテゴリがOSにメモリを解放するのか、それとも今までに増えるのかを知ることはできませんでした。デフォルトの最大値は1gのように見えます。これは、-XX:MaxMetaspaceSizeオプションで制御できます。注:これを指定すると、圧縮クラススペースも指定する必要はありません。

圧縮クラススペース

これはメタスペースに関連する表示されます。私は、このカテゴリがOSにメモリを解放するのか、それとも今までに増えるのかを知ることはできませんでした。デフォルトの最大値は1gのように見えます。これは '-XX:CompressedClassSpaceSize`オプションで制御できます。

ガベージコレクタのオーバーヘッド

選択ガベージコレクタに依存するオーバーヘッドの一定量、ならびにヒープのサイズに基づいて、追加の割り当てがあるように見えます。観測は、このオーバーヘッドがヒープサイズの約5%であることを示しています。これを制限するためのオプションはありません(別のGCアルゴリズムを選択する以外に)。

スレッド

各スレッドの埋蔵そのスタック用1メートル。 JVMは、スタックオーバーフローに対する安全対策として、50mを追加予約しているようです。スタックサイズは-Xssオプションで制御できます。安全サイズは制御できません。最大スレッド数を強制する方法はなく、各スレッドに一定量のメモリが必要なため、このメモリプールは技術的に無制限です。

Jarファイル(およびzipファイル)

デフォルトのzip実装では、zipファイルにアクセスするためのメモリマッピングを使用します。つまり、アクセスされた各jarファイルとzipファイルはメモリマップされます(ファイルサイズの合計に等しい量の予約済みメモリが必要です)。この現象は

NIO直接バッファ

-Dsun.zip.disableMemoryMapping=trueのように)sun.zip.disableMemoryMappingシステムプロパティを設定することによって無効にすることができる(allocateDirectを使用して作成された)直接的なバッファは、オフヒープメモリの量を使用します。最高のNIOパフォーマンスにはダイレクトバッファが付いているので、多くのフレームワークがそれらを使用します。

JVMは、NIOバッファに許可されるメモリの総量を制限する方法を提供しないため、このプールは技術的に制限されていません。

さらに、このメモリは、バッファに接触するスレッドごとに複製されます。詳細はthisを参照してください。あなたが任意のネイティブライブラリを使用している場合、彼らは割り当てる任意のメモリがオフヒープになりますライブラリ

によって割り当てられた

ネイティブメモリ。一部のコアJavaライブラリ(java.util.zip.ZipFileなど)は、メモリを消費するネイティブライブラリも使用します。

JVMは、ネイティブライブラリによって割り当てられるメモリの総量を制限する方法を提供しないため、このプールは技術的に制限されていません。

のmallocアリーナ

JVMは、これらのネイティブメモリ要求の多くにmalloc関数を使用しています。スレッドの競合の問題を回避するため、malloc関数は複数の事前割り当てプールを使用します。プールのデフォルト数は8 x cpuですが、環境変数MALLOC_ARENAS_MAXを設定すると上書きできます。すべてのプールが使用されていなくても、各プールは一定量のメモリーを予約します。

ほとんどの場合、ヒープから割り当てが行われるため、MALLOC_ARENAS_MAXを1-4に設定するのが一般的です。無駄な仮想メモリがulimitにカウントされないようにするために、

このカテゴリは、技術的には自分のプールではありませんが、余分なメモリの仮想割り当てについて説明しています。

関連する問題