4

Web アプリケーションのパフォーマンスをテストしていて、「メモリ不足エラー」(ネイティブ メモリ) が発生しました。

私は何度かテストしましたが、そのたびに「Chunk::new に 83886088 バイトを割り当てられませんでした」と死亡しました。

毎分メモリ サイズを出力したところ、プロセスが終了する前に VmSize が 2924700 kB であることがわかりました。

プロセスサイズの制限に達したと思います。-Xmx2000m を -Xmx1900m に変更すると、これで問題ありません。

いくつかの質問:

1.プロセスサイズ制限に達したことの確認方法 正確には3Gメモリではありません。

2.JVM が毎回 83886088 バイトのメモリを割り当てるのはなぜですか? 例外スタックから、GC 関係のようです。

3.ヒープ メモリ (-Xmx) と非ヒープ メモリ (-XX:MaxPermSize) 以外に、JVM 用に予約する必要があるメモリの数は? そして、それが現在使用している数を知る方法は?

私の貧弱な英語に感謝し、申し訳ありません。

Linux 2.6.16.60-0.83.2-bigsmp JRE 6.0_25-b06 Tomcat 7.0.37

jvm options: -Xms2000m -Xmx2000m -XX:PermSize=256M -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

/proc/meminfo:
MemTotal:     24935548 kB
MemFree:      13564968 kB

# Native memory allocation (malloc) failed to allocate 83886088 bytes for Chunk::new
# Possible reasons:
#   The system is out of physical RAM or swap space
#   In 32 bit mode, the process size limit was hit
...
# This output file may be truncated or incomplete.
#
#  Out of Memory Error (allocation.cpp:317), pid=18217, tid=275671968

---------------  T H R E A D  ---------------

Current thread (0x105a1c00):  VMThread [stack: 0x10666000,0x106e7000] [id=18243]

Stack: [0x10666000,0x106e7000],  sp=0x106e5ae0,  free space=510k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x724710]  VMError::report_and_die()+0x2b0
V  [libjvm.so+0x2f68ef]  report_vm_out_of_memory(char const*, int, unsigned, char const*)+0x4f
V  [libjvm.so+0x1576fc]  Chunk::operator new(unsigned, unsigned)+0x5c
V  [libjvm.so+0x157c26]  Arena::grow(unsigned)+0x26
V  [libjvm.so+0x6457e9]  resource_allocate_bytes(unsigned)+0x49
V  [libjvm.so+0x3a03ef]  GenericGrowableArray::raw_allocate(int)+0xbf
V  [libjvm.so+0x3402ee]  GrowableArray<oopDesc*>::grow(int)+0x3e
V  [libjvm.so+0x3a62b1]  FindInstanceClosure::do_object(oopDesc*)+0x51
V  [libjvm.so+0x2ae571]  CompactibleFreeListSpace::object_iterate(ObjectClosure*)+0x51
V  [libjvm.so+0x38d066]  GenerationObjIterateClosure::do_space(Space*)+0x16
V  [libjvm.so+0x2d6498]  ConcurrentMarkSweepGeneration::space_iterate(SpaceClosure*, bool)+0x18
V  [libjvm.so+0x38be22]  Generation::object_iterate(ObjectClosure*)+0x22
V  [libjvm.so+0x2d9f9d]  ConcurrentMarkSweepGeneration::object_iterate(ObjectClosure*)+0x4d
V  [libjvm.so+0x37fd65]  GenCollectedHeap::object_iterate(ObjectClosure*)+0x55
V  [libjvm.so+0x3a61fe]  HeapInspection::find_instances_at_safepoint(klassOopDesc*, GrowableArray<oopDesc*>*)+0x3e
V  [libjvm.so+0x6eca91]  ConcurrentLocksDump::dump_at_safepoint()+0xf1
V  [libjvm.so+0x6e7561]  Threads::print_on(outputStream*, bool, bool, bool)+0x201
V  [libjvm.so+0x734927]  VM_PrintThreads::doit()+0x27
V  [libjvm.so+0x734576]  VM_Operation::evaluate()+0x46
V  [libjvm.so+0x733a23]  VMThread::evaluate_operation(VM_Operation*)+0x83
V  [libjvm.so+0x733c90]  VMThread::loop()+0x190
V  [libjvm.so+0x733780]  VMThread::run()+0x80
V  [libjvm.so+0x5e294e]  java_start(Thread*)+0x14e
C  [libpthread.so.0+0x54ab]  short+0x8b

VM_Operation (0x0caff000): PrintThreads, mode: safepoint, requested by thread 0x09ec3800


---------------  P R O C E S S  ---------------

Java Threads: ( => current thread )
...//209 Java Threads

Heap
 par new generation   total 147456K, used 126550K [0x161f0000, 0x201f0000, 0x201f0000)
  eden space 131072K,  92% used [0x161f0000, 0x1d869d18, 0x1e1f0000)
  from space 16384K,  31% used [0x1e1f0000, 0x1e70be78, 0x1f1f0000)
  to   space 16384K,   0% used [0x1f1f0000, 0x1f1f0000, 0x201f0000)
 concurrent mark-sweep generation total 1884160K, used 1697819K [0x201f0000, 0x931f0000, 0x931f0000)
 concurrent-mark-sweep perm gen total 262144K, used 61769K [0x931f0000, 0xa31f0000, 0xb31f0000)

Code Cache  [0xb391f000, 0xb44b7000, 0xb691f000)
 total_blobs=3924 nmethods=3719 adapters=157 free_code_cache=38272704 largest_free_block=9600
4

3 に答える 3

3

毎分メモリ サイズを出力すると、プロセスが終了する前に VmSize が 2924700 kB であることがわかりました。

AFAIK Linux では、OS は約 1 GB を使用します。スレッド スタック、共有ライブラリ、Perm Gen、メモリ マップ ファイル、およびネイティブ リソース用の仮想メモリが必要です。

この制限に近づいている場合 (または 64 ビット プロセッサしか使用していない場合) は、64 ビット OS と JVM を使用する必要があります。Java 7 アップデート 25 ではないにしても、無償サポートが終了する Java 6 アップデート 45 を使用します。

于 2013-09-05T08:03:55.040 に答える
1

プロセスサイズ制限

最新の Linux OS は、物理アドレス拡張 (PAE)と呼ばれるものを使用することで、32 ビット バージョンの場合に 4 GB を超える RAM を使用できます。

しかし、何もしなければ、3GB はプロセスがヒットする合理的な制限のように思えます。

とはいえ、これはあなたのケースとはまったく関係ありません。エラーはカーネル (コア ダンプを取得していない) からではなく、Java ランタイムからのものです。

GC でこれが発生する理由は、他のスレッドが別の 83886088 バイトの空きメモリを要求し、残りがなかったからです。そのため、VM は GC を開始してスペースを空けました。残念ながら、すべてのオブジェクトがまだ使用されていました -> メモリ不足エラー。

JVM が毎回 83886088 バイトのメモリを割り当てるのはなぜですか?

ソフトウェアは決定論的であるべきです。つまり、実行するたびに同じ結果が得られるべきです。

他のスレッドを見てください。そのうちの 1 人が、このメモリを正確に割り当てようとしました。

ヒープ メモリ (-Xmx) と非ヒープ メモリ (-XX:MaxPermSize) 以外に、JVM 用に予約する必要があるメモリの数は?

それは、アプリケーションが何をするかによって異なります。しかし、通常、メモリ不足は、メモリ リークがあることを意味します (つまり、実際にはもう必要のない大きなオブジェクトが何かに保持されています)。

MATYourKitなどのプロファイラーを使用して、それが何であるかを判断します。

そして、それが現在使用している数を知る方法は?

jconsoleまたはVisualVMを使用してメモリ使用量を監視します。

関連している:

于 2013-09-05T08:15:22.733 に答える
0

-Xss=Nフラグを使用して、スレッドのスタック サイズを変更してみてください(例: -Xss=256k )。Linux のデフォルトのサイズは320 KBです(64 ビット マシンではサイズは 1 MB です)。通常、ネイティブ メモリ不足は次の理由で発生します。

スタックサイズを変更すると、1 と 2 の場合に役立つことに注意してください。

  1. 32 ビット JVM では、プロセスは 4 GB (OS によってはそれ以下) の最大サイズになります。
  2. システムは実際に仮想メモリを使い果たしました。
  3. Unix スタイルのシステムでは、ユーザーは (実行中のすべてのプログラム間で) ログイン用に構成された最大数のプロセスを既に作成しています。その点で、個々のスレッドはプロセスと見なされます。

お役に立てれば。

よろしく、ピナキ

于 2015-06-15T15:33:53.450 に答える