简体   繁体   English

JVM 崩溃,错误=“无法分配内存”(errno=12)

[英]JVM crashes with error='Cannot allocate memory' (errno=12)

My code crashes with this error message我的代码因此错误消息而崩溃

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)

There is insufficient memory for the Java Runtime Environment to continue.没有足够的内存供 Java 运行时环境继续使用。 Native memory allocation (malloc) failed to allocate 2712666112 bytes for committing reserved memory.本机内存分配 (malloc) 未能为提交保留内存分配 2712666112 字节。 An error report file with more information is saved as: /tmp/jvm-29955/hs_error.log`包含更多信息的错误报告文件保存为:/tmp/jvm-29955/hs_error.log`

Here is the content of the generated hs_error.log file :以下是生成的hs_error.log file的内容:

https://pastebin.com/yqF2Yy4P https://pastebin.com/yqF2Yy4P

This line from crash log seems interesting to me:崩溃日志中的这一行对我来说似乎很有趣:

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

Does it mean that the machine has memory but is running out of swap space?这是否意味着机器有内存但交换空间不足?

Here is meminfo from the crash log but I don't really know how to interpret it, like what is the difference between MemFree and MemAvailable?这是崩溃日志中的 meminfo,但我真的不知道如何解释它,比如 MemFree 和 MemAvailable 之间有什么区别? How much memory is this process taking?这个过程占用了多少内存?

/proc/meminfo : /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

Possible solutions:可能的解决方案:

  • Reduce memory load on the system减少系统内存负载
  • Increase physical memory or swap space增加物理内存或交换空间
  • Check if swap backing store is full检查交换后备存储是否已满
  • Use 64 bit Java on a 64 bit OS在 64 位操作系统上使用 64 位 Java
  • Decrease Java heap size (-Xmx/-Xms)减少 Java 堆大小 (-Xmx/-Xms)
  • Decrease number of Java threads减少 Java 线程数
  • Decrease Java thread stack sizes (-Xss)减少 Java 线程堆栈大小 (-Xss)
  • Set larger code cache with -XX:ReservedCodeCacheSize=使用 -XX:ReservedCodeCacheSize= 设置更大的代码缓存
  • In case you have many contexts wars deployed on your tomcat try reduce them如果您在 tomcat 上部署了许多上下文战争,请尝试减少它们

正如Scary Wombat 所提到的,JVM 试图分配 2712666112 字节(2.7 Gb)的内存,而您只有 691424000 字节(0.69 Gb)的空闲物理内存,交换中没有任何可用空间。

Another possibility (which I encountered just now) would be bad settings for "overcommit memory" on linux.另一种可能性(我刚才遇到的)是 linux 上“过量使用内存”的错误设置。

In my situation, /proc/sys/vm/overcommit_memory was set to "2" and /proc/sys/vm/overcommit_ratio to "50" , meaning "don't ever overcommit and only allow allocation of 50% of the available RAM+Swap".在我的情况下, /proc/sys/vm/overcommit_memory设置为 "2" 和/proc/sys/vm/overcommit_ratio为 "50" ,意思是“不要过度使用,只允许分配 50% 的可用 RAM +交换”。

That's a pretty deceptive problem, since there can be a lot of memory available, but allocations still fail for apparently no reason.这是一个相当具有欺骗性的问题,因为可能有大量可用内存,但分配仍然毫无理由地失败。

The settings can be changed to the default (overcommit in a sensible way) for now (until a restart):现在(直到重新启动)可以将设置更改为默认值(以合理的方式过度使用):

echo 0 >/proc/sys/vm/overcommit_memory

... or permanently: ...或永久:

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

Note: this can also partly be diagnosed by looking at the output of /proc/meminfo :注意:这也可以通过查看/proc/meminfo的输出来部分诊断:

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

In the example in the question, Committed_AS is much higher than CommitLimit , indicating (together with the fact that allocations fail) that overcommit is enabled, while here both values are close together, meaning that the limit is strictly enforced.在问题的示例中, Committed_AS远高于CommitLimit ,表明(连同分配失败的事实)启用了过度使用,而此处两个值接近在一起,这意味着严格执行限制。

An excellent detailed explanation of these settings and their effect (as well as when it makes sense to modify them) can be found in this pivotal blog entry .在这个关键的博客条目中可以找到对这些设置及其效果(以及何时修改它们有意义)的出色详细说明。 (Tl;dr: messing with overcommit is useful if you don't want critical processes to use swap) (Tl; dr:如果您不希望关键进程使用交换,那么处理过度使用会很有用)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM