今天,在部署外网的测试环境时,发现启动时报如下错误:


Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c6d80000, 42991616, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 42991616 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /home/username/hs_err_pid19325.log

根据 JVM 的日志 提示,很明显是因为内存不足,导致分配内存给 JVM 时启动失败。

因为平时都一直可以启动成功的,为什么今天却报因为内存问题而导致项目启动失败。

top

查看当前系统的进程状态,发现有一个 Java 进程:3679,属于 wxsdk 项目的,占用了 23% 的内存(物理内存为 8GB),这个值得注意,因为平时这些 Java 进程的内存,一般只是占用%几的内存的。

free -m

查看当前系统的总内存状态:


free -m
             total       used       free     shared    buffers     cached
Mem:          3953       3254        698          0         28         73
-/+ buffers/cache:       3152        800
Swap:            0          0          0

dump 出 wxsdk 的 heap 状态


jmap -dump:format=b,file=/tmp/heap.hprof 3670

然后下载回地本,使用 Eclipse 的 MAT 分析:


/Applications/mat.app/Contents/MacOS/MemoryAnalyzer -vmargs -Xmx8g -XX:-UseGCOverheadLimit heap.hprof

MAT 结果

MAT 报告的问题有:

Problem Suspect 1


The classloader/component "org.apache.catalina.loader.WebappClassLoader @ 0xc2578048" occupies 11,875,448 (31.20%) bytes. The memory is accumulated in classloader/component "org.apache.catalina.loader.WebappClassLoader @ 0xc2578048".

Keywords
org.apache.catalina.loader.WebappClassLoader @ 0xc2578048

Problem Suspect 2


The classloader/component "org.apache.catalina.loader.StandardClassLoader @ 0xc25e67d8" occupies 3,954,080 (10.39%) bytes. The memory is accumulated in one instance of "org.apache.tomcat.util.bcel.classfile.ConstantUtf8$1" loaded by "org.apache.catalina.loader.StandardClassLoader @ 0xc25e67d8".

Keywords
org.apache.tomcat.util.bcel.classfile.ConstantUtf8$1
org.apache.catalina.loader.StandardClassLoader @ 0xc25e67d8

Details »

Problem Suspect 3


5,236 instances of "java.lang.Class", loaded by "<system class loader>" occupy 4,494,072 (11.81%) bytes. 

Keywords
java.lang.Class

分析结果及结论

从上面的 MAT 的结果可知,是因为 Tomcat 的 ClassLoader 的问题,导致内存过大。而 ClassLoader 的问题,一般来说有如下两种情况:

  • 要加载的类本身就过多

  • 因为热加载,导致加载的 class 过多

然后查看 Tomcat 的配置文件 Tomcat 目录/conf/server.xml,发现 <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> 中的autoDeploytrue,表示 Tomcat 会自动进行热加载。

解决

  • 关闭 Tomcat 的热加载autoDeploy=false

  • 重新启动 wxsdk 项目,以释放这些内存空间