最近在使用 tomcat 的时候,总是在shutdown出现error='Cannot allocate memory' (errno=12)错误。起初只当是偶然因素引起的,所以没有重视。可是后来发现每次都会出现这个错误,所以这次决心找到原因解决。
第一步
首先观察报错信息如下:
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000eaaa0000, 357957632, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 357957632 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /home/gaea/tomcat-api/hs_err_pid14638.log
看#里面的内容,主要表达:Java 运行所需内存不足,本地内存分配为提交保留的内存分配失败。看到这里,突然想到之前在 catalinn.sh 中更改过虚拟机的启动参数,如下:
JAVA_OPTS="-Xms512m -Xmx1024m -Xss1024K"
第二步
分析错误信息:
- 众所周知,-Xms 表示堆的大小,-Xmx 表示堆的最大值。当 Java 虚拟机的堆内存不够时,就会向操作系统请求保留的堆内存,即堆的最大值与当前堆大小的差值。这样设置的目的是为了让虚拟机有更好性能收缩弹性,但是在这里适得其反了,因为当前 tomcat 运行的主机内存为 2GB。除了tomcat 之外,系统中还运行着其他服务,这就导致在 Java 虚拟机向操作系统请求分配保留的堆内存时,系统无法分配。
- 这里就引出了第二个问题,为什么只是shutdown的时候才出现报错,而 tomcat 没有宕掉。这是因为在shutdown时,需要单独一个进程来运行关闭tomcat时的一些操作,所以需要更多的内存,恰恰这些需要分配的内存超过了本地内存的上限,导致分配失败。所谓『压死骆驼的最后一根稻草』。
第三步
既然知道了问题的原因,解决起来就比较方便了,直接在 catalina.sh 中将虚拟机启动参数修改如下:
JAVA_OPTS="-Xms512m -Xmx512m -Xss1024K"
这样就解决问题了。
思考
通过上诉问题的解决,可以得出结论:
- 不要在内存吃紧的情况下,采用 -Xmx的方式动态分配堆内存。
版权声明:本文为博主原创文章,未经博主允许不得转载。
https://www.jianshu.com/p/08ca8dc4b5f0