Java应用无响应、内存飙升、CPU飙升排查

文章目录

      • 一、概述
        • 内存飙升:
        • CPU飙升:
        • 内存飙升常见原因:
        • CPU飙升常见原因:
      • 二、分析思路
        • 内存飙升:
          • 1.排查进程占用内存
          • 2.分析内存使用情况
          • 3.排查线程阻塞
        • CPU飙升:
      • 三、实际操作
        • 内存飙升:
          • 1.排查进程占用内存
          • 2.分析内存使用情况
            • > Dump快照
            • > GC日志
          • 3.排查线程阻塞
            • 检查连接数
        • CPU飙升:
          • 定位消耗CPU最高代码
      • 四、GC调优

一、概述

内存飙升:

  • 内存泄漏(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,堆积导致内存溢出。
  • 内存溢出 (out of memory):是指程序申请内存时,没有足够的内存供申请者使用,导致数据无法正常存储到内存中。

CPU飙升:

CPU飙升会导致系统响应缓慢甚至服务不可用。top命令查看cpu,cpu飙升导致服务假死。

内存飙升常见原因:

  • 其他应用(Redis、Kafka)占用总内存;

    解决:top命令排除。

  • 启动参数内存值设定的过小;

    解决:-Xms,-Xmx。

  • 内存中加载的数据量过于庞大(数据缓存、PDF字体缓存、文件传输);

    解决:代码走查,观察内存波动。

  • List、MAP等集合中对对象的引用,使用完后未清空,使得JVM不能回收;

    解决:代码走查,观察内存波动。

  • 代码中存在死循环或循环产生过多重复的对象实体;

    解决:代码走查。

CPU飙升常见原因:

  • 死循环、递归

    消耗CPU。

  • 正则

    消耗CPU。

  • 线程数

    线程数增多,通常会伴随内存飙升,但是线程内本身无复杂业务,会呈现,只有CPU飙升,但内存增高不明显。

  • 死锁

    死锁会导致核心线程数无响应,间接导致线程数飙升。

二、分析思路

内存飙升:

1.排查进程占用内存
  • 使用ps命令查看内存占用情况。
2.分析内存使用情况
  • 使用jstat工具查看Full GC情况,分析full gc次数是否频繁,确认应用本身是否有问题。

  • 使用jmap查看当前应用进程使用内存,分析是否存在内存飙升等问题。

3.排查线程阻塞
  • 使用netstat检查应用的连接数,排除线程阻塞原因。

CPU飙升:

top定位消耗CPU最高进程,jstack找到具体代码位置。

三、实际操作

内存飙升:

1.排查进程占用内存

方法一:

# 第五列为虚拟内存占用情况,第六列为实际内存占用情况,默认单位kb。
ps -aux | grep MyApp.jar
# 实际内存以M为单位
ps -aux | grep MyApp.jar | awk '{sum=$6/1024} {print $0 " " $1 " " sum " MB"}'

方法二:

# 通过ps查找进程id
ps -ef | grep MyApp.jar
# 通过top -p命令查看内存占用
top -p <pid>
2.分析内存使用情况

Java Heap Dump 是特定时刻 JVM 内存中所有对象的快照。它们对于解决内存泄漏问题和分析 Java 应用程序中的内存使用情况非常有用。

Java Heap Dump 通常以二进制格式的 hprof 文件存储。我们可以使用 jhat 或、JVisualVM 、MAT之类的工具打开和分析这些文件。

> Dump快照

1.生成dump快照

  • 自动生成dump快照信息:

    在OOM的时候会自动生成快照信息。

    java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/tmp/heapdump.hprof -jar MyApp.jar
    
  • 手动生成dump快照信息:

    如果启动脚本没有配置dump日志,不要直接停掉应用,手动生成dump日志。JVM 生成 Heap Dump 的时候,虚拟机是暂停一切服务的。如果是线上系统执行 Heap Dump 时需要注意。

    # 0.查看PID
    ps -aux | grep MyApp.jar
    jps
    ###################################
    # 1.1生成dump日志
    jmap -dump:format=b,file=/tmp/jmap_heapdump.hprof <pid>
    # 1.2生成dump日志(live只保留存活的对象),如果运行时间长,防止heap过大
    jmap -dump:live,format=b,file=/tmp/heapdump.hprof <pid>
    ###################################
    # jcmd是java 8引入的集大成的诊断工具。
    # 使用jcmd生成dump日志
    jcmd <pid> GC.heap_dump /tmp/jcmd_heapdump.hprof
    

2.解析dump日志

  • MAT(免费,解析Dump日志,得出可疑分析报告)

    Memory Analyzer Tool,下载失败,多点几次就行了。Memory Analyzer1.13.0需要jdk11。

    官网地址:https://www.eclipse.org/mat/

  • JProfiler(付费,可试用10天,连接应用直观分析JVM各种变化)
    官网:https://www.ej-technologies.com/download/jprofiler/files
    富贵码:

      # 12.0版本
      L-J12-STALKER#5846458-y8bdm6q8gtr7b#228a 
      L-J12-STALKER#8338547-qywh5933xu2r3#a4a4 
    
  • visualvm(免费)

    官网:https://visualvm.github.io/

    github:https://github.com/oracle/visualvm

> GC日志
  • 启动参数配置生成gc日志:

    java -Xloggc:gc.log -jar MyApp.jar
    
3.排查线程阻塞
检查连接数
netstat -nap | grep <pid>

CPU飙升:

定位消耗CPU最高代码
# 1.找到cpu最高的进程的id
top -c
# 查询java进程前五并进行排序
ps aux|grep java|grep -v grep|head -5|awk '{print $3,$1,$2}'|sort -rn
# 2.打印这个进程的所有线程的运行堆栈
jstack -l <pid> > /tmp/jstack.log
# 3.当前进程所有线程消耗情况
top -H -p <pid>
ps -mp <pid> -o THREAD,tid,time
# 4.找到CPU负载最高的线程, 把线程ID转换成16进制,(10进制转16进制,printf "%x\n" tid)
printf "%x\n" <tid>
# 5.搜索16进制显示的线程ID,定位到具体代码
vim jstack.log
# -A100是日志行数
# jstack |grep 16进制线程号 -A100

四、GC调优

  • jmap:查看内存信息

    # 查看新生代老年代
    jmap -heap pid
    # 生成dump文件
    jmap -dump:live,format=b,file=/tmp/heapdump.hprof <pid>
    
  • Jstack:进程、线程、堆栈

    # 打印这个进程的所有线程的运行堆栈
    jstack -l <pid>
    # 输出heap的直方图,包括类名,对象数量,对象占用大小
    jmap -histo <pid>
    # 输出堆内存设置和使用情况(JDK11使用jhsdb jmap --heap --pid pid)
    jmap -heap <pid>
    
  • Jinfo:查看jvm的参数

    Jinfo <pid>
    
  • Jstat:堆内存各部分的使用量,以及加载类的数量

    # 输出gc信息,包括gc次数和时间,内存使用状况
    jstat -gc <pid>
    jstat -gcutil <pid>
    
  • Jcmd:从JDK 7开始提供,jcmd拥有jmap的大部分功能,官方推荐使用jcmd命令替代jmap命令。

    # 列出所有的JVM进程
    jcmd -l 
    # 针对指定的进程,列出支持的所有命令
    jcmd <pid> help 
    

你可能感兴趣的:(J2EE,JVM,java,jvm,开发语言)