文章目录
cpu飙高排查
CPU 飙高的几种常见场景:
- 死循环
- 垃圾回收频繁触发
- 锁竞争(死锁)
- 高频率 I/O 操作
- 大规模的对象序列化/反序列化
- 高并发请求下线程池耗尽
- JVM 参数不合理
- 内存泄漏导致的 Full GC 频繁触发
1. 确认 CPU 占用高的进程
确认问题进程:使用 top
或 htop 命令来查看哪个进程占用了较高的 CPU,找到占用CPU最高的Java进程。
2. 查看进程的线程情况
确认哪个线程占用了高 CPU,可以使用 top -H
来查看单个线程的 CPU 使用情况:
top -Hp <PID>
这里,<PID>
是在第 1 步中找到的 Java 进程 ID。找到占用 CPU 高的线程,并记录下其线程 ID (TID)。注意,TID 是十进制表示的。
3. 将线程 ID 转换为十六进制
Java 堆栈通常使用十六进制来表示线程 ID。需要将高 CPU 占用的线程 ID 转换为十六进制:
printf "%x\n" <TID>
例如,假设线程 ID 是 12345
,则运行:
printf "%x\n" 12345
输出的结果是十六进制的线程 ID,比如 3039
。
4. 生成 Java 线程 dump
使用 jstack
命令生成 Java 进程的线程 dump。
jstack <PID> > jstack_output.txt
其中 <PID>
是第 1 步中找到的 Java 进程 ID。这个命令会生成当前 Java 进程的所有线程的堆栈信息,并将输出保存到 jstack_output.txt
文件中。
5. 分析线程 dump
打开生成的 jstack_output.txt
,搜索第 3 步中得到的十六进制线程 ID (0x3039
)。找到对应的线程堆栈信息。
堆栈信息中会显示该线程正在执行的 Java 方法,可以根据这些信息分析是什么代码逻辑导致了 CPU 占用过高。
总结
- 确认问题进程:使用
top
或htop
找到 CPU 占用高的 Java 进程。 - 查看线程情况:使用
top -Hp <PID>
查看该进程的各个线程 CPU 占用情况,记录高 CPU 占用线程的 TID。 - 转换线程 ID:将 TID 转换为十六进制,使用
printf "%x\n" <TID>
。 - 生成线程 dump:使用
jstack <PID>
生成线程堆栈,保存至文件。 - 分析堆栈信息:在 dump 文件中搜索十六进制 TID,分析该线程的执行方法,排查高 CPU 的原因。
内存溢出(OutOfMemoryError)
OutOfMemoryError
(简称OOM)是Java虚拟机(JVM)在无法分配足够内存时抛出的错误。当JVM中的内存耗尽,无法为新对象或数组分配空间时,就会抛出这个错误。
一、OOM的常见类型
OutOfMemoryError
有多种类型,排查时需要通过日志或异常信息确定具体的内存溢出原因。常见类型包括:
- Java Heap Space:Java 堆内存不足,无法分配对象。
- Metaspace/PermGen Space:类的元数据空间不足(JDK 8 之后为 Metaspace,之前为 PermGen)。
- GC Overhead Limit Exceeded:垃圾回收频率过高,JVM 花费太多时间进行垃圾回收,且回收效果不佳。
- Direct Buffer Memory:直接内存不足。
- Unable to Create New Native Thread:系统线程资源耗尽,无法创建新的线程。
二、OOM的常见原因
内存泄漏
- 对象不再使用但仍被引用,导致GC无法回收
- 常见于静态集合、缓存、监听器等场景
堆大小设置不合理
- -Xmx设置过小,无法满足应用需求
- 未根据应用实际情况调整JVM参数
大对象/大数组
- 一次性加载大量数据到内存
- 处理大文件时未使用流式处理
高并发场景
- 大量请求同时处理,创建过多对象
- 线程池设置不合理,创建过多线程
三、JVM OOM 排查手段
首先查看日志,java.lang.OutOfMemoryError 日志包含具体的 OOM 类型。
1、使用 jstat 查看 GC 情况
jstat -gc
命令,你可以快速获取 JVM 的垃圾回收统计信息。
场景:
场景1:内存泄漏诊断:OU持续增长,即使Full GC后也不下降 → 可能存在内存泄漏
场景2:新生代配置不合理:YGC非常频繁(每秒多次)且每次回收量少 → 考虑增大新生代
场景3:系统停顿问题:FGCT突然增大 → 检查是否有大对象直接进入老年代
2、jmap:生成堆转储文件
当应用遇到 OutOfMemoryError
时,生成堆内存 Dump 文件是排查内存泄漏或异常内存使用的第一步。生成堆内存 Dump 后,可以使用内存分析工具对 dump 文件进行深入分析。(用 jvisualvm 等工具)
方式1:手动生成 Dump:如果应用还在运行中但内存使用异常高,可以通过以下命令手动生成 dump 文件:
jmap -dump:format=b,file=heapdump.hprof <PID>
方式2: 在 JVM 启动参数中添加如下配置:
bash -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<路径>
这样,当发生 OutOfMemoryError
时,JVM 会自动生成堆内存 dump 文件,保存所有对象的当前状态。(有时候内存溢出后程序直接中断,所以需要通过 vm 参数的方式获取 Dump 文件)
3、VisualVM,JConsole等工具