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

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

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

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

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

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

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

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

top
  • 操作技巧:输入top后,按「P」键(大写),可以按CPU占用率从高到低排序,一眼就能找到“罪魁祸首”进程。
  • 关键说明:如果是Java服务,进程名一般是java,记住对应的PID(比如12345),后续用得上。

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

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

top -H -p 12345  # 12345替换为第一步找到的PID
  • 核心作用:-H参数会将进程拆分到线程级别,按「P」键排序后,就能找到占用CPU最高的线程ID(TID,比如12346)。

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

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

printf "%x\n" 12346  # 12346替换为第二步找到的TID
  • 示例:假设转换后得到的16进制线程ID是303a(注意小写,jstack日志中是小写)。

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

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

jstack 12345 | grep 303a -A 20  # 12345是进程PID,303a是16进制线程ID,-A 20表示显示后续20行
  • 关键解读:日志中会显示该线程正在执行的代码行、方法名,顺着堆栈信息找下去,就能快速定位到导致CPU飙高的具体代码(比如死循环、频繁GC等)。

小提示:排查完成后,记得点赞收藏,下次遇到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"
  • 灵活调整:根据自己项目的日志格式,修改时间匹配规则(比如yyyy-MM-dd HH:mm:ss、MM-dd HH:mm等)。

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. 先搞懂:僵尸进程是什么?怎么产生?

  • 定义:僵尸进程是指子进程已经终止,但父进程没有调用wait()或waitpid()函数回收子进程资源,导致子进程残留的“空壳进程”。
  • 核心原因:父进程异常退出、父进程逻辑缺陷(未回收子进程)、子进程执行时间过短,父进程还没来得及回收。

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

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

ps -ef | grep defunct  # defunct是僵尸进程的标识
# 或者更精准的筛选
ps aux | awk '{if($8=="Z") print $0}'
  • 输出解读:筛选结果中,STAT列显示为Z的,就是僵尸进程,记住对应的PID和父进程PID(PPID)。

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飙高、僵尸进程和磁盘满的资料请关注脚本之家其它相关文章!

相关文章

  • Java ThreadPool的使用解析

    Java ThreadPool的使用解析

    这篇文章主要介绍了Java ThreadPool的使用解析,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-10-10
  • java 实现增量同步和自定义同步的操作

    java 实现增量同步和自定义同步的操作

    这篇文章主要介绍了java 实现增量同步和自定义同步的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • IDEA Maven Dependencies出现红色波浪线的原因与解决

    IDEA Maven Dependencies出现红色波浪线的原因与解决

    在使用 IntelliJ IDEA 开发 Java 项目时,尤其是基于 Maven 的项目,开发者可能会遇到 Maven Dependencies 中出现红色波浪线的问题,本文我们就来看看这一现象的原因与解决吧
    2025-06-06
  • Mybatis通过数据库表自动生成实体类和xml映射文件

    Mybatis通过数据库表自动生成实体类和xml映射文件

    这篇文章主要介绍了Mybatis通过数据库表自动生成实体类和xml映射文件的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • 详解Java @Documented注解的作用

    详解Java @Documented注解的作用

    @Documented和@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,本文将通过示例详细说说@Documented注解的作用,需要的可以参考一下
    2022-09-09
  • Java并发之条件阻塞Condition的应用代码示例

    Java并发之条件阻塞Condition的应用代码示例

    这篇文章主要介绍了Java并发之条件阻塞Condition的应用代码示例,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-02-02
  • Java 如何调用long的最大值和最小值

    Java 如何调用long的最大值和最小值

    这篇文章主要介绍了Java 如何调用long的最大值和最小值的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • java数字图像处理基础使用imageio写图像文件示例

    java数字图像处理基础使用imageio写图像文件示例

    这篇文章主要介绍了Java 2D的图像处理API,文章讨论和提及的API都是基于JDK6的,Java中写一个图像文件使用ImageIO对象即可,下面看代码吧
    2014-01-01
  • 关于idea中ssm框架的编码问题分析

    关于idea中ssm框架的编码问题分析

    在实际开发中需要将操作系统编码、文件编码、页面编码以及tomcat服务器编码保持一致,而tomcat在默认情况下是使用UTF-8,这就使得其打印的日志文件出现中文乱码,因此在一般情况下,只需要将tomcat服务器的编码改为GBK即可
    2021-06-06
  • 浅析Java 并发编程中的synchronized

    浅析Java 并发编程中的synchronized

    这篇文章主要介绍了Java 并发编程中的synchronized的相关资料,帮助大家更好的理解和学习Java并发编程,感兴趣的朋友可以了解下
    2020-12-12

最新评论