最近遇到一个很头疼的问题,发布到测试服务器的tomcat中跑的java应用,频繁无故停止,并且查询catalina.out日志中并没有tomcat停止的相应记录,后来在主机的/var/log/messages文件中发现了端倪,原来是被linux 的OOM kill掉了,下面是tomcat被kill掉的截图记录
看到记录后开始思考为什么tomcat应用的vm总内存可以达到7G之多,要知道我的服务器的总内存才8G,且其上还运行了其他的应用,首先想到的是发生了内存泄露,于是开始配置jvm参数,打开gc日志以及溢出记录,以下是我设置jvm启动参数(jdk8)
vim tomcat8/bin/catalina.sh 文件最上面添加以下
JAVA_OPTS='-Xms512m -Xmx512m -XX:MetaspaceSize=128m -XX:MaxDirectMemorySize=40m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/wilson/dump -XX:+PrintGCDetails -Xloggc:/wilson/gc.log -XX:+PrintGCTimeStamps'
参数解释:
-Xms512m 初始化jvm堆内存大小
-XmX512m jvm堆内存最大值
-XX:MetaspaceSize=128m 初始化元空间内存大小(此处由于我使用的是jdk1.8,官方改用元空间替换原来的持久代,默认对于64位的server vm该值的初始值为21m,在jvm启动时,一旦元空间的值达到21m,便会触发Full GC 去卸载没有用的类,然后该值的大小会重置,新值的大小将取决与 GC 后释放了多少元空间,若释放的空间不足,会充值并提升该值的大小,若释放的空间过多,则降低该值的大小,所以如果该值的初始化值过小,会导致在jvm启动时频繁的触发Full GC去调整,即会导致启动时间增加)
-XX:MaxMetaspaceSize 最大元空间大小,默认没有上线,取决于主机的内存
-XX:MaxDirectMemorySize=40m 最大nio堆外内存大小(注意该参数只是限制nio堆外内存,堆外内存占用还有其他的部分)
-XX:+HeapDumpOnOutOfMemoryError 开启堆内存溢出生成dump文件
-XX:HeapDumpPath=/wilson/dump 生成dump文件位置
-XX:+PrintGCDetails 开启生成gc详细日志
-Xloggc:/wilson/gc.log gc文件日志
-XX:+PrintGCTimeStamps 设置开启gc时间格式
参数配置完毕重启tomcat,观察gc情况以及是否发生内存泄露
启动完毕后,查询tomcat进程的pid :
netstat -apn | grep <你的tomcat端口>
再命令行输入: jmap -heap
JProfiler安装链接:JProfiler安装并连接linux服务器
那么,问题来了,究竟是什么原因引起的tomcat内存占用将近7个g的呢?继续往下看
猜想可能是发生其他堆外内存泄露,导致tomcat占用内存飙升。分析堆外内存的话需要通过google-perftools分析了
google-perftools安装连接:google-perftools安装
安装完google-perftools之后,重启tomcat,持续观察其内存占用情况,未完待续......