Skip to content

进程管理与资源监控 ​

本篇定位

覆盖进程查看、信号、内存/CPU/负载排查、计划任务。

高频面试题 ​

Q1:CPU 使用率高如何排查? ​

我的答案:

CPU 高我按"先定位进程、再定位线程、再看在干什么"三步查。

第一步上 top:进交互界面后按 P 让进程按 CPU 从高到低排,先揪出是哪个进程吃 CPU。按 1 可以展开每个核心,看是单核打满还是整体忙。top 上方这行很关键:us(用户态)高是应用自己算得多,sy(内核态)高是系统调用/上下文切换多,wa(iowait)高说明 CPU 在等磁盘 IO——这三种情况根因完全不同。

第二步如果是 Java/多线程程序,要往下钻到线程:用 top -Hp <pid> 看这个进程里哪个线程在烧 CPU,拿到线程 ID 转成 16 进制,再 jstack <pid> | grep <16进制tid> 看这个线程在跑哪段代码。

第三步看它到底在干嘛:CPU 高但你不确定原因,可以 strace -p <pid> 看它在频繁发什么系统调用,或者用 perf top 看热点函数。

举个真实场景:us 高、某个 Java 进程占满,多半是死循环或者频繁 Full GC;sy 高可能是上下文切换太频繁(用 vmstat 看 cs 列);wa 高其实不是 CPU 的锅,是磁盘慢,该去查 IO。所以我第一句话永远是"先看 top 里 us/sy/wa 哪个高",这决定了后面往哪个方向查。


Q2:内存不足如何排查? ​

我的答案:

查内存我第一步永远是 free -h,而且重点看 available 那一列,不是看 free。

bash
free -h
#               total   used   free   shared  buff/cache  available
# Mem:           125Gi    20Gi    10Gi     1Gi        95Gi       100Gi

很多新人看到 free 只剩 10G 就慌了,其实不对——Linux 会把空闲内存拿去做磁盘缓存(buff/cache),这部分是"可回收"的,真正常用的是 available 列,它才是现在还能分给新程序的内存。所以 10G free + 95G cache ≈ 还有 100G 可用,根本不紧张。

如果 available 真的见底了,才是内存紧张。这时在 top 里按 M 让进程按内存从大到小排,揪出吃内存的进程。再深入:看 /var/log/messages 或 dmesg | grep -i oom,有没有内核 OOM killer 出来杀进程的记录——OOM 发生时内核会选一个"罪魁祸首"杀掉,日志里能看到杀了谁。

如果某进程内存只涨不跌,那是内存泄漏,需要抓 dump 分析。补充:swap 也要看,free 里 swap used 持续增长说明内存确实吃紧、在往磁盘上倒,性能会明显下降。一句话:先看 available 别被 cache 吓到,真紧张了按 M 找进程、查 OOM。


Q3:负载 load 高说明什么? ​

我的答案:

load average 是 Unix 系统的经典指标,但它的定义很多人搞不清。它不是 CPU 使用率,而是"处于运行态 + 不可中断睡眠态"的进程数的平均值,就是"正在抢资源排队的队伍长度"。

top 或 uptime 开头会给三个数:load average: 1.5, 0.8, 0.3,分别是过去 1 分钟、5 分钟、15 分钟的平均值。怎么解读要结合 CPU 核数:

  • 比如一台 8 核机器,load 是 8 才算打满,load 4 其实才用了一半。
  • 如果 load 10 但机器才 4 核,说明有 6 个进程在排队等。

关键在于:load 高不一定是 CPU 忙。因为不可中断睡眠的进程(通常是在等磁盘 IO)也算进 load。所以我看到 load 高,会先判断是哪种:

  • 同时 top 看 CPU 的 us/sy 高 → 确实是 CPU 计算瓶颈。
  • CPU 不高但 load 高,再看 wa(iowait)高 → 是磁盘 IO 拖慢,进程都卡在等盘上。
  • 也可能是大量进程在等锁、等 NFS。

还要看趋势:1 分钟 load 远高于 15 分钟,说明负载正在上来;反过来是在回落。所以我答 load 一定补一句"要结合核数和 iowait 一起看,不能单看数值大小"。


Q4:什么是僵尸进程?怎么处理? ​

我的答案:

僵尸进程是子进程已经退出了,但父进程没调用 wait() 去回收它的退出状态,于是这个子进程残留成一个占着 PID 的空壳,在 ps 里状态显示为 Z(zombie)。

它的原理是:进程退出时并不会立刻消失,内核会保留一个退出状态码,等着父进程来取。父进程不取,它就一直挂着。僵尸进程本身不占内存不占 CPU(资源已经释放了),只占一个进程号 PID——少量几个无所谓,但如果大量堆积,PID 被耗尽就没法再开新进程了,这才是危害。

排查:

bash
ps aux | grep defunct     # 或看 STAT 列是 Z 的

怎么处理?直接 kill 僵尸本身是杀不掉的,因为它已经死了。正确做法是找到它的父进程:

bash
ps -ef | grep <僵尸pid>    # 看 PPID 那列是哪个父进程

然后让父进程去回收——要么给父进程发 SIGCHLD 信号让它 wait,最干脆的办法是重启那个有 bug 的父进程,父进程一死,僵尸就被 init(PID 1)接管并回收了。

根因是父进程写得不对、没处理子进程退出。所以面试总结:少量僵尸是正常现象不用管,大量僵尸要找父进程修,治本是改父进程代码正确回收子进程。


相关链接 ​