web-dev-qa-db-ja.com

JVMがerror = 'Cannot allocate memory'(errno = 12)でクラッシュする

このエラーメッセージでコードがクラッシュする

Executing "/usr/bin/Java  com.utils.BotFilter"
OpenJDK 64-Bit Server VM warning: INFO: 
os::commit_memory(0x0000000357c80000, 2712666112, 0) failed; 
error='Cannot allocate memory' (errno=12)

Java Runtime Environmentを続行するためのメモリが不足しています。ネイティブメモリ割り当て(malloc)は、予約メモリをコミットするための2712666112バイトの割り当てに失敗しました。/jvm-29955/hs_error.log`

生成されたhs_error.log file

https://Pastebin.com/yqF2Yy4P

クラッシュログからのこの行は私にとって興味深いようです:

Memory: 4k page, physical 98823196k(691424k free), swap 1048572k(0k free)

マシンにはメモリはあるが、スワップ領域が不足しているということですか?

クラッシュログのmeminfoはここにありますが、MemFreeとMemAvailableの違いなど、どのように解釈すればよいのかわかりません。このプロセスはどのくらいのメモリを消費しますか?

/proc/meminfo

MemTotal:       98823196 kB
MemFree:          691424 kB
MemAvailable:    2204348 kB
Buffers:          145568 kB
Cached:          2799624 kB
SwapCached:       304368 kB
Active:         81524540 kB
Inactive:       14120408 kB
Active(anon):   80936988 kB
Inactive(anon): 13139448 kB
Active(file):     587552 kB
Inactive(file):   980960 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       1048572 kB
SwapFree:              0 kB
Dirty:              1332 kB
Writeback:             0 kB
AnonPages:      92395828 kB
Mapped:           120980 kB
Shmem:           1376052 kB
Slab:             594476 kB
SReclaimable:     282296 kB
SUnreclaim:       312180 kB
KernelStack:      317648 kB
PageTables:       238412 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    50460168 kB
Committed_AS:   114163748 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      314408 kB
VmallocChunk:   34308158464 kB
HardwareCorrupted:     0 kB
AnonHugePages:  50071552 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:      116924 kB
DirectMap2M:     5115904 kB
DirectMap1G:    95420416 kB
10
Generic Person

可能な解決策:

  • システムのメモリ負荷を減らす
  • 物理メモリまたはスワップスペースを増やす
  • スワップバッキングストアがいっぱいかどうかを確認する
  • 64ビットOSで64ビットJavaを使用
  • 減少Javaヒープサイズ(-Xmx/-Xms)
  • Javaスレッドの数を減らす
  • Javaスレッドスタックサイズ(-Xss)
  • -XX:ReservedCodeCacheSize =でより大きなコードキャッシュを設定します
  • Tomcatに多くのコンテキストwarがデプロイされている場合は、それらを減らしてみてください
6
Scary Wombat

もう1つの可能性(たった今遭遇した)は、Linuxでの「メモリーのオーバーコミット」の設定が不適切であることです。

私の状況では、/proc/sys/vm/overcommit_memoryが "2"に設定され、/proc/sys/vm/overcommit_ratioが "50"に設定されていました。

大量のメモリを使用できる可能性があるため、これは非常に誤解を招く問題です。しかし、割り当ては明らかに理由もなく失敗します。

現在、設定はデフォルトに変更できます(賢明な方法でオーバーコミット)(再起動まで):

echo 0 >/proc/sys/vm/overcommit_memory

...または永続的に:

echo "vm.overcommit_memory=0 >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf # apply it immediately

注:これは、/proc/meminfoの出力を調べることでも部分的に診断できます。

...
CommitLimit:    45329388 kB
Committed_AS:   44818080 kB 
...

質問の例では、Committed_ASCommitLimitよりもはるかに高く、(割り当てが失敗するという事実とともに)オーバーコミットが有効になっていることを示していますが、ここでは両方の値が近く、つまり制限が厳密に実施されます。

これらの設定とその効果に関する優れた詳細な説明(およびそれらを変更する意味がある場合)は、この pivotal blog entry にあります。 (Tl; dr:オーバーコミットを使用することは、重要なプロセスでスワップを使用したくない場合に便利です)

1
creinig

Scary Wombat が言及しているように、JVMは2712666112バイト(2.7 Gb)のメモリを割り当てようとしていますが、691424000バイト(0.69 Gb)の空き物理メモリしかなく、スワップで利用できるものはありません。

1