JDK内置命令工具

内存爆炸和CPU100%问题分析

当线上的系统突然请求缓慢, CPU100%, 内存占用巨大, 当JVM出现问题时,应该如何排查问题呢

问题排查

  1. 登录服务器, 使用top命令查看系统资源使用情况
    一般出问题时java程序的占用是最高的

  2. 找到CPU或者内存占用高的java进程PID, 使用命令top -Hp 进程ID, 查询该进程中线程的运行情况

  3. 使用printf "%x\n" 线程ID查看线程PID的16进制形式
    因为在java日志中记录的PID是16进制的形式

  4. jstack 进程ID > ./threadDump.log 打印JVM堆栈信息到文件threadDump.log中
    在该堆栈信息文件中,找到第3步的线程, 查看具体信息

  5. 使用jstat -gcutil 进程号 统计间隔时间 统计次数查看GC的变化情况, 当发现FGC的值一直增大时, 继续使用jmap -heap 进程ID 查看进程堆内存的情况, 特别是老年代的使用情况.
    老年代内存占用达到阈值时就会触发Full GC

  6. jmap -dump:format=b,file=filename 进程ID ,导出Java进程下内存堆到文件中, 再把内存镜像dump文件传到本地, 利用工具进行分析
    可以使用jhatVisualVM等工具分析dump文件

原因分析

Full GC次数过多

  1. jstat命令发现GC次数很多,并且不断增加
  2. 分析dump文件,查看具体对象的内存占用情况
    如果内存占用情况不多, 说明代码中频繁使用了System.gc()

代码中消耗CPU的操作太多

比如复杂的算法,递归的循环等,甚至是代码BUG

锁的使用不正确, 造成死锁

分析JVM堆栈信息,看是否有死锁deadlock

不定期的接口耗时现象

这主要是因为不定期的高并发带来的问题, 要通过压测工具不断加大访问力度, 发现某个接口某个位置响应缓慢, 再查看堆栈日志, 发现大量线程被阻塞在同一位置, 就能查到我们哪个业务代码出了问题