java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java线程CPU飙高、僵尸进程和磁盘满

Java线程CPU飙高、僵尸进程和磁盘满的排查技巧

作者:予枫的编程笔记

线上故障就像埋在系统里的定时炸弹——CPU突然飙高导致服务卡顿、海量日志找不到异常、磁盘满了直接宕机,每一种都能让程序员头皮发麻,所以今天整理了4类高频线上故障的排查套路,附实操命令,需要的朋友可以参考下

线上故障就像埋在系统里的“定时炸弹”——CPU突然飙高导致服务卡顿、海量日志找不到异常、磁盘满了直接宕机,每一种都能让程序员头皮发麻。
不用瞎试错,不用靠经验瞎猜,今天整理了4类高频线上故障的排查套路,附实操命令,从定位到解决一步到位,收藏起来,下次故障直接抄作业!

一、CPU飙高:快速定位到具体Java线程(实操拉满)

线上服务突然卡顿、接口响应超时,大概率是CPU飙高惹的祸。很多新手遇到这种情况,只会用top命令看一眼CPU占用,却不知道怎么定位到具体的代码线程,最后只能瞎折腾。

分享一套极简排查流程,从定位进程到找到异常线程,全程只需几行命令,新手也能快速上手👇

1. 第一步:定位CPU占用最高的进程

先用top命令查看系统CPU使用情况,重点关注%CPU列,找到占用率最高的进程(PID):

top

2. 第二步:定位进程中CPU占用最高的线程

找到异常进程后,用top -H -p 命令,定位该进程下占用CPU最高的线程(TID):

top -H -p 12345  # 12345替换为第一步找到的PID

3. 第三步:将线程ID转换为16进制(关键一步)

因为Java的jstack日志中,线程ID是16进制的,所以需要将第二步找到的TID(十进制)转换为16进制:

printf "%x\n" 12346  # 12346替换为第二步找到的TID

4. 第四步:用jstack打印日志,定位异常线程

最后用jstack命令打印该进程的线程日志,并用grep过滤出目标线程,就能找到异常代码的堆栈信息:

jstack 12345 | grep 303a -A 20  # 12345是进程PID,303a是16进制线程ID,-A 20表示显示后续20行

小提示:排查完成后,记得点赞收藏,下次遇到CPU飙高,直接按这个流程来,不用再翻资料!

二、日志分析:海量日志中快速定位异常(grep组合拳)

线上服务报错,日志文件动辄几百M、几个G,直接打开查找异常信息,不仅耗时,还容易看漏。

分享3个最实用的grep组合命令,帮你快速从海量日志中筛选出异常信息,效率翻倍👇

1. 基础用法:筛选包含指定关键词的日志

最常用的场景:查找包含“Error”“Exception”等异常关键词的日志,快速定位报错位置:

# 筛选包含Error的日志,显示行号
grep -n "Error" app.log

# 筛选包含Exception的日志,忽略大小写(比如Exception、exception都能匹配)
grep -i "Exception" app.log

2. 进阶用法:筛选指定时间段的日志

很多时候,我们知道故障发生的大致时间段,只需筛选该时间段内的日志,缩小查找范围:

# 假设日志格式是 2026-02-10 14:30:00 错误信息,筛选14:30-14:40之间的Error日志
grep "2026-02-10 14:3[0-4]" app.log | grep "Error"

3. 高阶用法:筛选异常日志并输出到文件

如果异常日志较多,可将筛选结果输出到单独的文件中,方便后续分析(避免反复执行命令):

# 筛选近1小时内的Exception日志,输出到error.log文件中
grep "2026-02-10 13:" app.log | grep -i "Exception" > error.log

小技巧:如果日志是滚动日志(比如app.log.1、app.log.2),可以用grep “关键词” app.log* 批量筛选所有日志文件。

三、僵尸进程:产生原因+清理方法(避免占用系统资源)

僵尸进程(Zombie)是线上常见的“隐形杀手”——它本身不占用CPU和内存,但会占用系统进程号(PID),如果大量堆积,会导致系统无法创建新进程,最终引发服务异常。

1. 先搞懂:僵尸进程是什么?怎么产生?

2. 第一步:查找系统中的僵尸进程

用ps命令筛选出僵尸进程,僵尸进程的状态标记为「Z」:

ps -ef | grep defunct  # defunct是僵尸进程的标识
# 或者更精准的筛选
ps aux | awk '{if($8=="Z") print $0}'

3. 第二步:清理僵尸进程(两种方法,按需选择)

清理僵尸进程的核心是“回收子进程资源”,优先用温和方法,避免影响正常服务:

方法1:重启父进程(推荐,温和安全)

僵尸进程是父进程未回收导致的,重启父进程后,系统会自动回收其下属的僵尸进程:

# 先查看父进程名称(PPID是父进程ID)
ps -ef | grep 1234  # 1234是父进程PPID
# 重启父进程(根据自己的服务启动方式调整)
systemctl restart 服务名  # 比如systemctl restart java-service

方法2:强制杀死父进程(紧急情况使用)

如果父进程无法重启,可强制杀死父进程,系统会将僵尸进程托管给init进程(PID=1),init进程会自动回收僵尸进程:

kill -9 1234  # 1234是父进程PPID,谨慎使用!

警告:强制杀死父进程会导致父进程对应的服务中断,仅在紧急情况下使用,提前做好备份。

四、磁盘满:inode耗尽与文件删除后空间未释放(坑点规避)

线上服务突然宕机,登录服务器后发现磁盘满了(df -h查看使用率100%),但删除大文件后,磁盘空间还是没释放——这两个坑,很多程序员都踩过。

1. 坑点1:文件删除后,空间未释放(原因+解决)

核心原因:

删除的文件正在被进程占用(比如日志文件被Java进程占用),此时rm命令只是删除了文件的目录项,文件的实际内容还在磁盘中,空间不会释放。

排查+解决步骤:

查找被占用的已删除文件:

lsof | grep deleted  # 筛选出已删除但仍被进程占用的文件

找到对应的进程(PID),重启该进程(释放文件占用):

systemctl restart 服务名  # 比如重启Java服务,释放日志文件占用

补充说明:如果无法重启进程,可通过echo “” > 文件名 的方式清空文件(避免删除文件导致的占用问题):

echo "" > app.log  # 清空日志文件,释放空间,且不影响进程占用

2. 坑点2:inode耗尽(磁盘有空间,但无法创建文件)

核心原因:

磁盘的inode节点耗尽了——inode是文件的索引,每个文件对应一个inode,即使磁盘有剩余空间,inode耗尽后,也无法创建新文件(报错:no space left on device)。

排查+解决步骤:

查看inode使用情况:

df -i  # 查看各分区inode使用率,Ifree列是剩余inode数量

定位inode占用最多的目录(找到大量小文件的目录):

# 从根目录开始查找,统计每个目录的inode数量
for i in /*; do echo $i; find $i | wc -l; done

解决方法:删除目录下的大量小文件(比如日志碎片、临时文件),释放inode:

# 批量删除指定目录下的小文件(谨慎操作,确认文件可删除)
rm -rf /tmp/*  # 比如删除/tmp目录下的临时文件

预防建议:定期清理临时文件、日志碎片,避免小文件堆积导致inode耗尽,可写定时脚本自动清理。

五、总结

线上故障排查的核心不是“瞎试错”,而是“找对逻辑、用对命令”——CPU飙高找线程、日志繁杂用grep、僵尸进程清父进程、磁盘满分两种坑点,按本文的套路来,大部分高频故障都能在10分钟内定位并解决。

以上就是Java线程CPU飙高、僵尸进程和磁盘满的排查技巧的详细内容,更多关于Java线程CPU飙高、僵尸进程和磁盘满的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文