由于是 阿里云的 ESC 没有权限看监控 面板 所以先跳过这步
日志:/var/log/message --一般oom信息这里会找到,但是排查没有相关kill和内存信息。参考命令dmesg
grep -i kill /var/log/messages*
dmesg |grep -E 'kill|oom|out of memory'
java -jar
-Xms4048m -Xmx4048m
-XX:MetaspaceSize=240M -XX:MaxMetaspaceSize=512M
-XX:NewSize=512m -XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSClassUnloadingEnabled -XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps
-Xloggc:/usr/local/tomcatGC/xlvip/tomcat_gc.log -XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/tomcatGC/xlvip/vip.hprof
business-vip-service.jar --spring.profiles.active=prod
-XX:+HeapDumpOnOutOfMemoryError
和 -XX:HeapDumpPath
及是否产生相关 堆 oom dumpXX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:/usr/local/tomcatGC/xlvip/tomcat_gc.log
相关 gc 日志hs_err_pid*.log
,分析例子打开 MAT 分析 head dump 堆信息 (没有的可以在这下载) 需要java11 (没有的可以在这下载)
配置 MAT 根目录下的 MemoryAnalyzer.ini 如果 本地环境变量是 java8 的话 需要配置 指定java11
-vm
C:\Program Files\Java\jdk-11.0.16+8\bin\
-startup
plugins/org.eclipse.equinox.launcher_1.6.400.v20210924-0641.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.2.400.v20211117-0650
-vmargs
-Xmx1024m
如果 堆dump 太大的话 可以 在服务器上配置好 MAT后 在MAT 文件目录下执行
# 根据需要调整java的路径,版本5或更高版本,以及堆大小。
用法:ParseHeapDump.sh <path/to/dump.dmp.zip> [report]*
该org.eclipse.mat.api:suspects参数创建一个包含泄漏嫌疑报告的 ZIP 文件。此参数是可选的。
该org.eclipse.mat.api:overview参数创建一个包含概览报告的 ZIP 文件。此参数是可选的。
该org.eclipse.mat.api:top_components参数创建一个包含顶级组件报告的 ZIP 文件。此参数是可选的。
# 如果爆 sh脚本错误 则 将脚本修改
java -Xmx4g -Xms4g \
-jar plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar \
-consoleLog -consolelog -application org.eclipse.mat.api.parse "$@"
例子
./ParseHeapDump.sh heapdump1.hprof org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components
等待结果…
结果会生产如下三个zip文件,很小可以直接拷贝到本机
jmap_Leak_Suspects.zip
jmap_System_Overview.zip
jmap_Top_Components.zip
有两种查看报告的方法
具体 MAT 详细深度用法 请看这里
将 GC日志 拖入 gceasy 内
分析GC 请看这里
jps
jstack -F pid > thread.txt
cat thread.txt |grep -10 deadlock
或者
printf %x pid
jstack 19663 | grep 10 线程 16进制
Java 系统调试则是一件截然不同的事,一个可以用于 Oracle 的 JVM 或其他 JVM 上的调试的技巧是你可以运行 kill -3
同时一个完整的栈轨迹和堆概述(包括 GC 的细节)会被保存到标准错误或是日志文件
nohup java -jar xxx.jar &
kill -3 PID
使用 jrf + sjk
生成火焰图
# 加上以下的这两个参数即可开启对应的JFR功能
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder
# 或者 使用java神器jcmd来开启JFR:
jcmd pid VM.unlock_commercial_features
# dump
jcmd pid JFR.dump filename=hotspot-pid-7-xxxx.jfr path-to-gc-roots=true
使用sjk 生成火焰图
java -jar /app/sjk.jar flame -f /app/hotspot-pid-7-xxxx.jfr -o /app/appdemo.html
复杂问题排查 请参考 我 另外一篇 Arthas docker内排查 java程序问题
-Xms4g 初始堆大小4g
-Xmx4g 最大堆大小4g
-XX:NewSize=1g 设置年轻代大小=1g
-XX:MaxNewSize=2g 年轻代最大值2g
-Xss256k 每个线程的堆栈大小256k
-XX:NewRatio=2 年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代), -XX:NewRatio=2表示年轻代与年老代所占比值为1:2,年轻代占整个堆栈的1/3
-XX:SurvivorRatio=8 Eden区与Survivor区的大小比值,设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:MetaspaceSize=256m 元数据空间的初始大小256m,java8后才有,将永久代替换为元数据区
-XX:+DisableExplicitGC 关闭System.gc()
-XX:MaxTenuringThreshold=15 垃圾最大年龄,如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率
-XX:+UseParNewGC 设置年轻代为并行收集
-XX:ParallelGCThreads=8 并行收集器的线程数为8,此值最好配置与处理器数目相等
-XX:ConcGCThreads=8 CMS垃圾回收器并行线程线,推荐值为CPU核心数。
-XX:+UseConcMarkSweepGC 老年代使用CMS内存收集
-XX:+UseBiasedLocking 启用一个优化了的线程锁,对于高并发访问很重要 ,太多的请求忙不过来它自动优化,对于各自长短不一的请求,出现的阻塞、排队现象,他自己优化。
-XX:+CMSParallelRemarkEnabled 降低标记停顿
-XX:CMSInitiatingOccupancyFraction=70 使用cms作为垃圾回收,使用70%后开始CMS收集
-XX:+PrintGCDetails 输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
-XX:+PrintGCTimeStamps 打印Gc时间戳
-Xloggc:logs/Gc.log 把相关日志信息记录到logs/GcLog.log文件以便分析
-XX:+HeapDumpOnOutOfMemoryError 出现堆内存溢出时,自动导出堆内存 dump 快照
-XX:HeapDumpPath=logs 设置导出的堆内存快照的存放地址为logs
-XX:+CMSClassUnloadingEnabled 开启回收Perm永生代
-XX:+UseCompressedClassPointers(压缩开关)
-XX:CompressedClassSpaceSize=512m(Compressed Class Space 空间大小限制)。-