生产环境突然频繁挂掉,查看日志报错OOM
光看日志没法确定原因,于是想把内存dump下来分析
首先来看看tomcat的启动脚本startup.sh,在tomcat的bin目录下(这里的版本是tomcat8.5)
启动过程中会去执行catalina.sh,以下是catalina.sh的部分内容
如果setenv.sh脚本存在的话,启动tomcat就会去执行这个脚本,这里很适合添加自定义的参数
vim setenv.sh 创建这个文件
写入:JAVA_OPTS="-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Xmx6144m -Xms6144m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/www/server/tomcat/oom_dump"
esc-->:-->wq
-Dfile.encoding:指定文件内容编码格式
-Dsun.jnu.encoding:指定文件名的编码格式
-Xmx6144m:设置JVM可用最大内存为6114M
-Xms6144m:设置JVM初始内存大小为6114M
ps:这个服务器的内存为8G,分配了6G给JVM,接近极限了。
-XX:+HeapDumpOnOutOfMemoryError :在发生OOM的时候保存快照
-XX:HeapDumpPath=/www/server/tomcat/oom_dump":快照保存地址“/www/server/tomcat/oom_dump”
ps:这里一定要确认tomcat是否有权限对该文件夹进行修改,比如我这里是用www用户启动的tomcat,我用root用户登录服务器创建了/www/server/tomcat/oom_dump文件夹,默认权限是需要root权限才能访问的,setenv.sh文件也一样要注意权限问题。
命令groups [用户名] 可以查询用户所属的组,直接输入groups是查询当前登录用户的组
修改文件夹所属的组和用户,使用命令:
chown 用户名:组名 文件夹名/文件名
chown www:www /www/server/tomcat/oom_dump
chown www:www /www/server/tomcat/bin/setenv.sh
用户名没有冲突的话也可以直接使用chown www /www/server/tomcat/oom_dump
果不其然再次OOM。。T_T
找到/www/server/tomcat/oom_dump/java_pid12907.hprof
下载下来,然后推荐使用eclipse的MemoryAnalyzer(MAT)来分析,简单好用
打开eclipse-->help-->Eclipse Marketplace,搜索MemoryAnalyzer-->Install
MAT教程:https://www.cnblogs.com/UncleYong/p/7743294.html#MySignature
ps:依据快照文件大小可能需要调整eclipse的配置
打开eclipse安装目录-->找到eclipse.ini-->编辑,将-Xmx调大,我的快照文件是1.5G,我这里调大至-Xmx4096m,eclipse的JVM内存小于快照文件大小会导致打不开。
打开MAT面板
Open Heap Dump -->选择快照文件会得到如下视图:
1.Histogram可以列出内存中的对象,对象的个数以及大小。
2. Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
3.Top consumers通过图形列出最大的object。
4.Leak Suspects通过MA自动分析泄漏的原因。
点击Dominator Tree
这里我点开最大占用的对象
发现是嵌套ArrayList,里面全是字符串,占用了将近700M(原本服务器设置的最大堆内存为2G)
最终找到了引发OOM的类,查找到了原因,业务是加载oss上的文件,读取文件内容存入List再转成json返回给前端,但是该文件太大了。
修改接口为只返回文件路径给前端,点击查看才尝试加载文件,如果大小超过2M则提示不支持预览,请下载后查看。
另外Leak Suspects-->Details-->See stacktrace也能定位到问题发生的位置。
本文有不当之处还请各位看官不吝赐教,感谢查看。
原文地址:https://www.cnblogs.com/zou-rong/p/11952825.html