生产环境问题快速排查

1、Java线上CPU过高

排查核心逻辑

先定位高CPU进程

→再定位进程内高耗CPU线程

→导出线程栈分析代码逻辑

→定位问题代码

→针对性优化根治,全程基于Linux服务器命令行操作,贴合生产无界面部署场景。

第一步:定位高CPU消耗Java进程

登录目标服务器,执行top命令查看系统进程占用情况,找到CPU使用率长期居高不下、远超正常阈值的Java进程,记录进程PID(PID为数字唯一标识);也可使用top -c 命令,展示完整进程启动命令,精准区分多个Java服务进程。

第二步:定位进程内高耗CPU线程

执行命令 top -Hp 目标Java进程PID,筛选出该进程下CPU占用最高的线程,记录对应线程PID;后续需将该线程PID转换为十六进制格式,执行 printf "%x\n" 线程PID 命令,获取十六进制线程ID,用于后续线程栈匹配。

第三步:导出Java进程线程栈信息

使用JDK自带工具jstack导出目标Java进程完整线程栈,执行命令 jstack -l Java进程PID > cpu_stack.log,将线程栈日志输出至文件,方便后续检索分析;建议连续导出2-3次线程栈,避免单次采样偏差,精准定位持续运行的异常线程。

第四步:匹配线程ID,定位问题代码

通过less、grep命令检索线程栈日志,查找第二步获取的十六进制线程ID,定位对应线程堆栈信息;重点关注RUNNABLE状态、无等待阻塞、持续占用CPU的线程,查看堆栈中业务代码行号、循环逻辑、死循环、频繁GC、密集计算等异常代码片段。

第五步:常见高CPU问题归类与根治

核心问题场景:代码死循环/无限循环、高频递归调用、大量正则表达式回溯、密集型计算未异步、频繁Full GC、线程池线程数量不合理、自旋锁无限重试;针对对应代码逻辑修改,优化循环条件、拆分密集计算、合理设置GC参数、调整线程池参数,完成后重启服务验证CPU占用。

2、Java内存过高、OOM异常

排查核心逻辑

先确认内存溢出/高占用现象

→开启JVM内存监控参数

→导出堆转储快照 (收集信息会占用大量内存,建议从负载均衡中限制进入,消耗,摘除该节点)

→分析堆内存对象占用→定位大对象、内存泄漏代码

→优化内存使用、修复泄漏问题,区分内存溢出(OOM)、内存占用持续走高两种场景。

第一步:前置准备,开启JVM监控参数

服务启动时提前配置JVM参数,方便问题发生时自动导出快照,避免重启丢失现场:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/指定快照存储路径,同时配置-Xms、-Xmx内存参数,合理划分堆内存大小,监控GC日志:-XX:+PrintGC -XX:+PrintGCDetails -Xloggc:gc.log。

第二步:定位内存异常进程

通过top命令查看Java进程RES(物理内存)、VIRT(虚拟内存)占用,确认内存持续上涨、触发OOM异常的Java进程PID;同步查看GC日志,判断是否存在Full GC频繁、GC后内存无法释放、老年代占比持续爆满的情况。

第三步:导出堆内存转储快照

若服务未自动导出快照,手动执行命令 jmap -dump:format=b,file=heap_dump.hprof Java进程PID,生成堆快照文件;注意:生产环境导出快照会短暂暂停服务,建议在低峰期操作,或基于副本服务排查,避免影响线上业务。

第四步:分析堆快照,定位问题根源

使用JVisualVM、MAT(Memory Analyzer Tool)工具打开hprof快照文件,重点分析:对象占用内存排行、大对象列表、GC Roots引用链、泄漏可疑对象;定位未释放的连接、静态集合缓存、长生命周期对象持有短生命周期对象、线程池资源未释放、循环创建对象等内存泄漏问题。

第五步:内存问题分类优化

  • 内存溢出OOM:优化大对象创建、避免无限缓存、及时关闭流/连接、释放无用对象引用、调整堆内存大小;

  • 内存占用过高:优化缓存策略、定时清理无用数据、合理使用线程池、避免频繁创建对象、修复内存泄漏代码;

  • GC异常:优化JVM垃圾收集器、调整新生代老年代比例、减少Full GC频次。

第六步:验证优化效果

重启服务后,持续监控内存占用、GC日志,观察内存走势是否平稳、Full GC是否减少、无OOM异常抛出,确认问题彻底根治。

3、Arthas排查生产环境

场景1:CPU负载过高、服务器卡顿

1. 全局监控:执行dashboard,查看实时进程面板,锁定高CPU线程;

2. 定位线程:thread -n 5,查看占用CPU最高的5个线程,获取线程ID;

3. 查看栈信息:thread 线程ID,查看线程完整堆栈,定位业务代码位置;

4. 追踪方法耗时:trace 全类名 方法名,排查方法内部调用耗时,定位慢逻辑。

场景2:接口响应慢、方法执行超时

1. 定位耗时方法:trace 全类名 方法名,逐层排查内部调用耗时,过滤JDK自带方法可加-j参数;

2. 查看入参出参:watch 全类名 方法名 '{params,returnObj,throwExp}',查看请求参数、返回结果、异常信息;

3. 统计调用数据:monitor -c 5 全类名 方法名,每5秒统计一次方法调用次数、成功率、平均耗时;

4. 查看调用链路:stack 全类名 方法名,查看当前方法被哪些方法调用,梳理调用栈。

场景3:线程死锁、线程阻塞

1. 一键查找阻塞线程:thread -b,直接定位阻塞其他线程的锁线程;

2. 查看全局线程状态:thread,查看所有线程状态、阻塞时长、锁信息;

3. 分析锁竞争:结合线程栈,定位锁冲突代码,优化锁逻辑。

场景4:类冲突、代码不生效、配置不生效

1. 查看类加载信息:sc -d 全类名,查看类是否被加载、所属jar包、类加载器;

2. 反编译线上代码:jad 全类名,查看当前服务器运行的真实代码,确认是否与部署包一致;

3. 查看类方法:sm 全类名,查看类下所有方法信息,确认方法签名是否正确;

4. 查看系统配置:sysprop、sysenv,查看JVM系统属性、环境变量,排查配置加载问题。

场景5:线上隐性异常、日志无报错但业务失败

1. 捕获方法异常:watch 全类名 方法名 '{throwExp}' -e -n 10,捕获异常并打印堆栈,最多监听10次;

2. 记录调用现场:tt -t 全类名 方法名,记录方法入参、出参、异常信息,支持后续回放;

3. 回放调用现场:tt -i 记录ID -p,复现问题调用,精准定位问题。

场景6:内存异常、GC频繁

1. 实时查看GC状态:gc,查看堆内存、GC次数、耗时;

2. 查看JVM详情:jvm,查看堆内存分配、垃圾收集器类型、类加载数量;

3. 导出堆快照:heapdump /tmp/heap.hprof,导出内存快照,后续借助工具分析内存泄漏。

4、Arthas命令集合

常用命令

基础监控命令

# 实时系统面板(CPU、内存、线程、GC,排查首选)
dashboard
# 查看JVM详细信息
jvm
# 实时查看GC情况
gc
# 查看系统属性
sysprop
# 查看系统环境变量
sysenv

线程排查命令

# 查看所有线程信息
thread
# 查看CPU占用最高的N个线程
thread -n 数值
# 查找阻塞线程(死锁专用)
thread -b
# 查看指定线程堆栈
thread 线程ID

类与方法排查命令

# 搜索已加载类
sc 全类名(支持通配符*)
# 查看类详细加载信息
sc -d 全类名
# 查看类方法信息
sm 全类名
# 反编译线上代码
jad 全类名
# 查看类加载器统计
classloader

方法监控与耗时排查(最常用)

# 追踪方法内部调用耗时
trace 全类名 方法名
# 过滤JDK方法,只看业务代码耗时
trace -j 全类名 方法名
# 监控方法入参、返回值、异常
watch 全类名 方法名 '{params,returnObj,throwExp}'
# 定时统计方法调用指标
monitor -c 间隔秒数 全类名 方法名
# 查看方法调用栈
stack 全类名 方法名

异常与调用回放命令

# 监听方法异常
watch 全类名 方法名 '{throwExp}' -e
# 记录方法调用现场
tt -t 全类名 方法名
# 回放指定调用
tt -i 记录ID -p

辅助运维命令

# 导出堆内存快照
heapdump 文件存储路径
# 修改JVM运行参数
vmoption
# 执行OGNL表达式,调用静态方法、查看静态变量
ognl '@全类名@静态变量/方法'
# 退出控制台
quit
# 彻底关闭Arthas
stop

redefine热更新

前提说明(高危红线)

  • 仅限紧急修复,业务低峰期操作,禁止改类名、方法名、属性结构、接口

  • 提前备份原 class 文件,做好重启回滚兜底

  • 热更新不持久,重启服务失效,后续需部署正式包

本地修改并编译新 Class

修复代码 bug,不改动类结构(仅改方法内逻辑)

编译生成新的 .class 文件

把 class 文件上传到服务器(随便放,记好路径)

进入 Arthas 控制台

已绑定目标 Java 进程,保持 arthas 命令行窗口在线

执行热更新命令

# 格式:redefine 服务器class绝对路径

redefine /usr/local/app/UserServiceImpl.class

# 相对路径示例(class在当前目录)

redefine ./UserServiceImpl.class

出现 redefine success 即为替换成功

验证 + 回滚

验证

  • 调用对应接口测试修复效果

  • 反编译核对:jad 全类名

回滚

  • 上传原备份 class,重新执行 redefine

  • 失效直接重启 Java 服务

常见报错 & 解决

  • redefine 失败,类结构已修改:本地代码别改方法 / 属性名,重新编译

  • 找不到 class 文件:检查路径、文件权限

  • 类被锁定无法替换:低峰期重试,或重启服务

退出清理

热更新完成后,正常退出即可

quit # 退出控制台

stop # 彻底关闭arthas

生产使用注意事项

  1. 生产环境禁止随意使用redefine热更新代码,避免引发服务异常;

  2. 导出堆快照、执行大批量监控命令时,选择业务低峰期,避免影响服务性能;

  3. 排查完毕务必执行stop命令,解除进程绑定,防止占用服务器资源;

  4. 多Java进程服务器,启动后仔细核对进程序号,避免绑定错误服务;

  5. 权限不足时,使用sudo提升权限,防止启动、绑定进程失败。

5、SkyWalking 高频实用操作

  1. 按 TraceID 精准检索:快速定位单次请求全链路

  2. 耗时筛选:大于 1s/5s,批量定位慢接口

  3. 异常筛选:只看 Error 链路,高效定位报错

  4. 拓扑图:查看服务依赖、调用方向、异常节点

  5. 数据库监控:查看慢 SQL、执行次数、DB 响应耗时

  6. 实例监控:查看单个服务实例的指标,排查单实例故障

  7. 日志关联:日志打印 %X{tid}(TraceID),实现链路 + 日志联动

  8. 告警查看:历史告警、触发规则(响应超时、错误率过高)

【20260328】Java 高级 & 架构岗 面试核心清单 2026-03-28
【20260401】java面试题集合 2026-04-01