Java 一次启动失败分析案例
Contents
今天,在部署外网的测试环境时,发现启动时报如下错误:
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">
中的autoDeploy
为true
,表示 Tomcat 会自动进行热加载。
解决
关闭 Tomcat 的热加载
autoDeploy=false
重新启动 wxsdk 项目,以释放这些内存空间