一次 线上 Java进程突然挂掉排查 过程思路

介绍

1. 查看系统资源占用情况

由于是 阿里云的 ESC 没有权限看监控 面板 所以先跳过这步

2 查看 系统内核是否触发oom机制。

日志:/var/log/message --一般oom信息这里会找到,但是排查没有相关kill和内存信息。参考命令dmesg

grep -i kill /var/log/messages*

dmesg |grep -E 'kill|oom|out of memory'

在这里插入图片描述

3. 查询Java应用程序是否触发的oom

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
  1. 先查找应用本身log 是否有 有“java.lang.OutOfMemoryError: Java heap space”等信息
  2. 查看JVM参数 -XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath及是否产生相关 堆 oom dump
  3. 查看JVM参数 XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:/usr/local/tomcatGC/xlvip/tomcat_gc.log 相关 gc 日志
  4. 查看 是否 存在 JVM crash log hs_err_pid*.log分析例子

MAT 分析 head dump 堆信息

打开 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

有两种查看报告的方法

  • 直接把zip下载到本地,然后解压用浏览器查看index.html
  • 把zip下载到本地, 用MAT可视化工具解析zip

具体 MAT 详细深度用法 请看这里

分析 GC 日志

将 GC日志 拖入 gceasy

分析GC 请看这里

cpu 飙升 死锁分析

  1. 通过jps确定当前执行任务的进程号: jps
  2. 执行jstack命令查看当前进程堆栈信息: jstack -F pid > thread.txt
  3. 查看是否存在 cat thread.txt |grep -10 deadlock

或者

  1. 先top -p 输入shift+p触发 cpu 占用最高的排序
  2. 然后 top -Hp pid 查看线程占用 ,算出 线程 16进制 printf %x pid
  3. 最后 jstack 19663 | grep 10 线程 16进制

小技巧

Java 系统调试则是一件截然不同的事,一个可以用于 Oracle 的 JVM 或其他 JVM 上的调试的技巧是你可以运行 kill -3 <pid> 同时一个完整的栈轨迹和堆概述(包括 GC 的细节)会被保存到标准错误或是日志文件

nohup java -jar xxx.jar &
kill -3 PID

使用 jrf + sjk 生成火焰图

  1. jfr 是一个低开销java分析框架,已经内置openjdk 11 中了,我们可以直接使用jcmd 进行应用的性能分析,
  2. sjk 瑞士军刀 用于 JVM 故障排除、监控和分析的小型工具集。
# 加上以下的这两个参数即可开启对应的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程序问题

在这里插入图片描述

附上 一个 jvm 比较全面的调优参数范例

-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 空间大小限制)。-
  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值