Javaプロセスでメモリを消費するものは何ですか?


20

中程度の負荷でのJavaプロセスのメモリ使用量を調査しようとしています。

  PID   USER    PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  12663 test    20   0 8378m 6.0g 4492 S   43  8.4 162:29.95 java

ご覧のとおり、6Gbに常駐メモリがあります。興味深い部分はこれです:プロセスはこれらのパラメータで実行されます:

  • -Xmx2048m
  • -Xms2048m
  • -XX:NewSize = 512m
  • -XX:MaxDirectMemorySize = 256m
  • ... GCおよびその他のもの

これらの設定と実際のメモリ使用量を見ると、このプロセスの使用が予想されるものと実際に使用されるものの違いを見つけるためにつまずきます。

通常、メモリの問題はヒープダンプを分析することで解決されますが、この場合、メモリはヒープ外のどこかで使用されます。

質問:このような高いメモリ使用量の理由を見つけて見つけるための手順は何ですか?そのプロセスでメモリを使用しているものを識別するのに役立つツールは何ですか?

編集0

まだかなりのスペースがあるので、これはヒープ関連の問題のようには見えません:

jmap -heap 12663

結果(スペースを節約するために編集)

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize      = 2147483648 (2048.0MB)
NewSize          = 536870912 (512.0MB)
MaxNewSize       = 536870912 (512.0MB)
OldSize          = 1610612736 (1536.0MB)
NewRatio         = 7
SurvivorRatio    = 8
PermSize         = 21757952 (20.75MB)
MaxPermSize      = 85983232 (82.0MB)

New Generation: 45.7% used
Eden Space: 46.3% used
From Space: 41.4% used
To Space: 0.0% used
concurrent mark-sweep generation: 63.7% used
Perm Generation: 82.5% used

編集1

pmapを使用すると、64Mbのかなりの量の割り当てがあることがわかります。

pmap -x 12663 | grep rwx | sort -n -k3 | less

結果:

... a lot more of these 64Mb chunks
00007f32b8000000       0   65508   65508 rwx--    [ anon ] <- what are these?
00007f32ac000000       0   65512   65512 rwx--    [ anon ]
00007f3268000000       0   65516   65516 rwx--    [ anon ]
00007f3324000000       0   65516   65516 rwx--    [ anon ]
00007f32c0000000       0   65520   65520 rwx--    [ anon ]
00007f3314000000       0   65528   65528 rwx--    [ anon ] 
00000000401cf000       0  241904  240980 rwx--    [ anon ] <- Direct memory ?
000000077ae00000       0 2139688 2139048 rwx--    [ anon ] <- Heap ?

それでは、これらの64Mbのチャンクがどのようにわかるのでしょうか?それらは何を使用していますか?それらにはどのようなデータがありますか?

ありがとう


2
私はまったく同じ問題を抱えていました...ここに私の質問があります。stackoverflow.com/questions/18734389/…これに関する解決策はありますか?
DeepNightTwo

回答:


21

問題は、このglibcの問題に関連している可能性があります。

基本的に、メモリを割り当てる複数のスレッドがある場合、glibcは利用可能なアリーナの数を増やしてロック競合を回避するために割り当てを行います。アリーナは64Mbの大きさです。上限は、コアアリーナの8倍の数を作成することです。アリーナは、スレッドが既にロックされているアリーナにアクセスするときにオンデマンドで作成されるため、時間とともに成長します。

スレッドを振りかけるJavaでは、これはすぐに多くのアリーナが作成されることにつながります。そして、これらのアリーナ全体に配分が広がっています。最初は、各64Mbアリーナはコミットされていないメモリにマップされますが、割り当てを行うと、実際のメモリが使用され始めます。

pmapには、おそらく以下のようなリストがあります。324K + 65212K = 65536K、560K + 64976K == 65536K、620K + 64916K == 65536Kであることに注意してください。つまり、合計で64Mbになります。

00007f4394000000 324K rw --- [anon]
00007f4394051000 65212K ----- [アノン]
00007f4398000000 560K rw --- [anon]
00007f439808c000 64976K ----- [アノン]
00007f439c000000 620K rw --- [anon]
00007f439c09b000 64916K ----- [アノン]

回避策として:バグには、アリーナの数を制限するために設定できるいくつかの環境パラメーターが記載されていますが、glibcバージョンが十分に高い必要があります。


5
XmxとXmsを同じ値に設定し、さらにWebサービスを開始するshスクリプトで環境変数「export MALLOC_ARENA_MAX = 4」を設定すると、この場合に役立ちました。それまでは、2〜8時間ごとにOOM KillerによるWebサービスの再起動が発生していました。それが仕事にMALLOC_ARENA_MAX設定の> = 2.16である必要がありますので、Ubuntuの14.04でGLIBCバージョンは、良いですが2.19である
Kluyg

この答えと上記のコメントは私にとって命の恩人でした。私の場合、MALLOC_ARENA_MAX = 1が必要かつ効果的でした。
ジョンバチル

3

どの程度Lamdbaプローブ?特に、以下のスクリーンショットのようなメモリ使用量の内訳を表示できます。

Lambdaプローブのメモリ使用量ビュー

時にはpmap -x your_java_pidも参考にすることができます。


ご回答有難うございます。正しく理解できれば、Lambda ProbeはApache Tomcat用ですか?我々は使用しない...私はトップのポストに情報を追加しますPMAPについて
コンスタンチンS.

2

JProfilerはあなたが探しているものかもしれませんが、無料ではありません。Javaプロセスのメモリ使用量を調査するためのもう1つの優れた無料のツールは、Oracle / Sun JDKディストリビューションでJDKツールとして利用可能なJava VisualVMです。私は個人的に、問題に対するより包括的なアプローチ(JDK + OS +ディスクの監視など)–ネットワーク監視システムの使用(Nagios、Verax NMS、またはOpenNMS)をお勧めします。


2
彼の漏れがあるオフヒープJProfilerをので、本当にここに助けにはなりません
アサフMesika

2

問題はヒープ外にあるため、最適な候補は次のとおりです。

JNI leak  
Allocation of direct memory buffer

ダイレクトバッファサイズが制限されているという事実により、私の意見ではJNIリークが最良の候補です。


1

jmapと呼ばれるJDKに含まれるヒープメモリの割り当てを表示する便利なツールがあります。さらに、スタックなど(Xss)もあります。次の2つのjmapコマンドを実行して、メモリ使用量に関する詳細情報を取得します。

jmap -heap <PID>
jmap -permstat <PID>

さらに多くの情報を取得するには、jconsole(JDKにも含まれています)を使用してプロセスに接続できます。ただし、Jconsoleでは、アプリケーションでJMXを設定する必要があります。


あなたの答えをありがとう、しかし問題はヒープ外のどこかにあるようです。私はjmapのからいくつかの情報を反映するために、トップのポストを更新します
コンスタンチンS.

プロセスにはいくつのスレッドがありますか?スタックサイズは、ほとんどのプラットフォームでデフォルトの2MBであるため、スレッド数で乗算します。すべての「失われた」メモリを占めているが、場合によってはその一部を占めている場合、私は驚くでしょう。
HampusLi

約300スレッド、pmapからの情報を取得すると、スタックサイズは1Mbです。そして、同じpmap出力から、これらのスタックが100Kb以上を使用しているようには見えない
Konstantin S.

0

JVisualVMを使用します。使用中のヒープメモリの量、PermGenなどを示すさまざまなビューがあります。

あなたの質問に答えることに関して。Javaは、予想とはまったく異なる方法でメモリを処理します。

-Xmsおよび-Xmxパラメーターを設定すると、開始時にヒープに割り当てるメモリ量と、最大値として割り当てる必要がある量をJVMに伝えることになります。

合計1mのメモリを使用し、-Xms256m -Xmx2gで渡されるJavaアプリケーションがある場合、JVMは256mのメモリを使用して自身を初期化します。それ以下を使用しません。アプリケーションが1mのメモリしか使用しないことは問題ではありません。

第二に。上記の場合、ある時点でアプリが256mを超えるメモリを使用する場合、JVMは要求を処理するために必要なだけのメモリを割り当てます。ただし、ヒープサイズは最小値に戻りません。少なくとも、ほとんどの状況ではそうではありません。

あなたの場合、最小および最大メモリを2gに設定しているため、JVMは開始時に2gを割り当て、それを維持します。

Javaのメモリ管理は非常に複雑であり、メモリ使用量の調整自体がタスクになる場合があります。ただし、役立つリソースがたくさんあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.