一堆进程 kill -9 都杀不掉:一次 Linux 僵尸进程排查复盘

一台服务器巡检时发现挂着三十多个状态为 Z 名字带 defunct 的进程,数字还在涨,kill 杀不掉连 kill -9 也杀不掉。排查梳理:僵尸进程 Z 状态带 defunct 已经死了不是活进程,代码停了内存释放了只占一个 PID 表项;子进程退出后内核保留一个极小的尸体记着退出码等父进程来取,父进程调 wait 或 waitpid 取走后内核才彻底回收尸体和 PID;kill 和 kill -9 杀不掉僵尸因为信号是发给活进程的,你没法杀死一个已经死了的进程;僵尸大量堆积只有一个原因父进程没调 wait 收尸,问题在它父进程;现场清僵尸靠重启父进程,父进程一死僵尸过继给 1 号进程 init,init 会立刻把它们收掉;根治在父进程代码处理 SIGCHLD 时 while waitpid 收尸或不关心退出码就设 SIG_IGN;别把 D 状态当僵尸,D 是活进程卡在内核不可中断 IO 里真杀不动要去查那个慢 IO;孤儿进程和僵尸是两回事且无害被过继给 init 有靠谱养父;僵尸虽不占 CPU 内存但堆积会漏 PID 极端时 fork 不出新进程;容器里应用常自己就是 1 号进程没收尸能力,用 docker run --init 注入 init,以及一套进程状态排查纪律。

2024 年,我接手维护一个跑了很久的后台服务。某天巡检,我习惯性地 ps 看了一眼进程,发现一个奇怪的现象:这台机器上,挂着一大串状态是 Z 的进程,名字后面都跟着一个刺眼的 <defunct>。我数了数,有三十多个,而且这个数字还在慢慢往上涨。我以前对 <defunct> 这个词只有个模糊印象,知道它叫"僵尸进程",但从没认真处理过。我第一反应是:进程嘛,杀掉就好。我挑了一个,kill 它——没反应;我换成 kill -9,这可是"必杀",连这个进程都不会放过的信号——结果还是没反应,那个 Z 状态的进程,纹丝不动地待在 ps 列表里。我连着 kill -9 了好几个,一个都杀不掉。一个连 kill -9 都"杀不死"的进程——这彻底颠覆了我的认知,在我朴素的理解里,kill -9 是没有任何进程能扛得住的。我盯着这一串杀不掉的僵尸想了很久,最后才意识到:我搞错了一件最根本的事——僵尸进程,它根本就不是一个"还活着、需要被杀掉"的进程;它早就死了。这件事逼着我把进程的生命周期、父子关系、wait() 回收这一整套彻底理清了。本文复盘这次实战。

问题背景

环境:CentOS 7,一个长期运行的后台服务
事故现象:
- ps 里挂着三十多个状态为 Z、名字带  的进程
- 这个数字还在缓慢上涨
- ★ kill 杀不掉,连 kill -9 也杀不掉

现场排查:
# 1. 看到一堆 Z 状态进程
$ ps -ef | grep defunct | grep -v grep
app  20131  9088  0 ... [worker]       # ★ Z 状态
app  20148  9088  0 ... [worker] 
app  20165  9088  0 ... [worker] 
... (三十多个)

# 2. ★ kill / kill -9 都杀不掉
$ kill -9 20131
$ ps -p 20131
  PID ... STAT
20131 ... Z                                     # ★ 还在,还是 Z

# 3. ★ 关键:看这些僵尸的【父进程】是谁(PPID 那一列)
$ ps -eo pid,ppid,stat,comm | grep -w Z
20131  9088  Z   worker
20148  9088  Z   worker
20165  9088  Z   worker
#       ^^^^ ★ 父进程 PPID 全是 9088 —— 同一个爹

# 4. ★ 看 9088 这个父进程是什么
$ ps -p 9088 -o pid,stat,comm
 PID STAT COMMAND
9088 Sl   mydaemon                               # ★ 父进程活得好好的

根因(后来想清楚的):
1. ★ 僵尸进程(Z / )【不是活着的进程】。
   它的代码早已停止运行、内存早已释放。它已经死了。
2. 一个子进程退出后,内核不会立刻把它彻底抹掉,
   而是【保留一个很小的"尸体"】—— 里面记着它的
   退出码等信息,等它的【父进程】来"收尸"。
3. ★ 父进程"收尸"的动作,就是调用 wait() 系列函数,
   把子进程的退出状态读走。读走之后,内核才会把这个
   "尸体"和它占的 PID 表项【彻底回收】。
4. 我这个服务的父进程 mydaemon,fork 出大量子进程
   干活,子进程干完就退出了 —— 但父进程的代码
   【忘了调 wait() 去回收】。于是子进程的尸体一具具
   堆积,就成了一片僵尸。
5. ★ kill -9 杀不掉僵尸,因为 kill 是发给【活进程】
   的信号 —— 而僵尸已经死了,没有代码在运行,信号
   没有任何东西可以作用。你没法"杀死一个死人"。
僵尸 ≠ 失控的活进程,僵尸 = 没人收尸的死进程。要动的是它父进程。

修复 1:僵尸进程到底是什么——它已经死了

# === ★ 纠正最大的误解:僵尸不是"活着的坏进程" ===

# === 我以为的 vs 真实的 ===
# 我以为:Z 状态的僵尸进程,是一个【出了问题、还在
#   占着资源、需要我杀掉】的活进程。所以我去 kill 它。
# ★ 真相:僵尸进程【已经死了】。它的程序代码早已
#   停止执行,它占的内存、打开的文件,内核都已经
#   回收干净了。它不消耗 CPU,也不消耗内存。
# ★ 它唯一还占着的,是进程表里的【一个表项】——
#   也就是【一个 PID 号】,外加一点点退出信息。

# === ★ 一个进程退出时,到底发生了什么 ===
# 一个子进程调 exit() 退出,内核做的事【分两步】:
# 1. ★ 立刻回收"重的东西":内存、文件描述符、各种
#    资源 —— 这些当场就释放了。
# 2. ★ 保留"轻的东西":一个极小的结构,记着它的
#    PID、退出码、运行了多久等。这就是"尸体"。
# 为什么要保留这个尸体?★ 因为它的【父进程】可能
#   想知道"我这个孩子是怎么退出的、退出码是几"。
#   内核得把这个信息留着,等父进程来取。

# === ★ "收尸":父进程调 wait() ===
# 父进程调用 wait() / waitpid() 这类函数,就是来
#   "取走子进程的退出状态"。这个动作一完成:
#  ★ 内核就把那个尸体、那个 PID 表项,彻底删掉。
#   僵尸,就这么"安葬"了。
# 一个进程从子进程退出、到父进程 wait 回收,中间
#   这段"已死、但还没被收尸"的时间,它就处于
#   Z(Zombie)状态 —— 显示为 。
# ★ 正常情况下,这个状态只是【一闪而过】的。

# === ★ 僵尸"堆积",是父进程没在收尸 ===
# 如果你看到僵尸【大量堆积、长期不消失】,只有一个
#   原因:它们的父进程,【没有】调用 wait() 去回收。
#   子进程一个个死了,却一个个没人收尸 —— 越堆越多。

# === 认知 ===
# ★ 僵尸进程的问题,从来不在僵尸自己身上(它已经
#   死了,无所谓了)。问题在它的【父进程】—— 是
#   父进程失职,没尽到"收尸"的责任。

修复 2:为什么 kill -9 也杀不掉僵尸

# === ★ 想通一件事:你没法"杀死一个已经死了的进程" ===

# === kill 到底是什么 ===
# kill 这个命令,名字有误导性。它实际做的事是:
#   ★ 向一个进程【发送一个信号】。
# kill 9527        -> 给 9527 发 SIGTERM(请求它退出)
# kill -9 9527     -> 给 9527 发 SIGKILL(强制它退出)
# 信号要起作用,前提是:★ 目标进程【还在运行】,
#   它(或内核替它)能【接收并处理】这个信号。

# === ★ 僵尸进程接收不了任何信号 ===
# 僵尸进程已经死了 —— 它没有代码在执行,它不是一个
#   "可被调度、可运行"的实体了。
# ★ 你给它发 SIGKILL,这个信号没有任何"活的东西"
#   可以作用 —— 就像你对着一具尸体喊"你给我倒下"。
#   它早就倒下了。SIGKILL 对它【完全无效】。
$ kill -9 20131
$ ps -p 20131 -o stat        # 还是 Z —— 信号根本没动它分毫

# === ★ 那僵尸到底怎么才能消失 ===
# 僵尸消失,只有一条路:★ 它的【父进程】调 wait()
#   把它的退出状态取走。除此之外,没有别的办法。
#  - kill 僵尸自己 -> 无效(它已经死了)。
#  - kill -9 僵尸自己 -> 同样无效。
# ★ 你能操作的,是它的【父进程】。

# === ★ 正确的着力点:找到父进程,让它去收尸 ===
# 思路有两个:
# 1. 给【父进程】发 SIGCHLD 信号 —— 提醒它"你有
#    孩子死了,快去 wait"。但★ 这招经常没用:如果
#    父进程的代码压根没写处理 SIGCHLD 的逻辑,
#    提醒了也白提醒。
$ kill -CHLD 9088            # 试试提醒父进程(常常无效)
# 2. ★ 真正可靠的一招:让【父进程】退出 / 重启。
#    见下一节 —— 这才是现场能立刻见效的办法。

# === 认知 ===
# ★ 对僵尸进程本身做任何事都是徒劳的。kill -9 杀不掉
#   它,不是它"强",是它"已经不在了"。所有动作,
#   都要对准它的【父进程】。

修复 3:现场怎么清掉一片僵尸

# === ★ 清僵尸:动父进程,分两种情况 ===

# === 第一步:先把"父进程"找出来 ===
# 僵尸的 PPID 那一列,就是父进程的 PID。
$ ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/'
20131  9088  Z   worker
20148  9088  Z   worker
#       ^^^^ ★ 父进程是 9088
# 看看 9088 是个什么进程:
$ ps -p 9088 -o pid,ppid,stat,comm,args

# === ★ 情况 A:父进程还活着 —— 重启父进程 ===
# 这是最常见的情况,也是现场最快的解法。
# ★ 重启那个【父进程】(不是僵尸!)。父进程一退出,
#   会发生一件很妙的事 ——
$ systemctl restart mydaemon      # 重启那个父服务
# 父进程死后,它名下那些僵尸子进程就"没爹"了。内核
#   会把这些孤儿(包括僵尸)统统【过继给 1 号进程】。
# ★ 1 号进程(init / systemd)是个尽职的"养父",
#   它有一个一直在 wait() 的循环,会立刻把过继来的
#   僵尸全部收尸。—— 僵尸瞬间清空。

# === ★ 情况 B:不能重启父进程 —— 先 kill 父进程的活子进程 ===
# 有时父进程不能停。可以试着【温和地提醒】它:
$ kill -CHLD 9088                 # 提醒父进程去 wait
# ★ 但这招能不能成,完全取决于父进程的代码有没有写
#   收尸逻辑。多数"会堆僵尸"的程序,恰恰就是没写,
#   所以这招经常无效。无效的话,还是得回到重启。

# === ★ 一个关键澄清:僵尸"占" PID,会不会撑爆系统 ===
# 系统的 PID 总数有上限:
$ cat /proc/sys/kernel/pid_max
32768
# 每个僵尸占 1 个 PID。如果僵尸无限堆积,极端情况下
#   会把 PID 耗光 —— 那时整个系统【fork 不出新进程】,
#   连 ls 都可能跑不起来。
# ★ 所以僵尸虽然"已经死了、不占 CPU 内存",但任由
#   它堆积,依然是个真问题 —— 它在慢慢漏 PID。

# === 验证 ===
$ ps -eo stat | grep -c Z         # Z 状态进程数,应归零
# ★ 重启父进程后,这个数字应该立刻变 0。

修复 4:Z 状态、D 状态、孤儿进程——别搞混

# === ★ 几个容易混淆的进程状态,一次理清 ===

# === ps 的 STAT 列,常见状态 ===
$ ps -eo pid,stat,comm
#  R  运行中 / 可运行
#  S  可中断睡眠(在等事件,绝大多数进程平时都是 S)
#  D  ★ 不可中断睡眠 —— 见下,这个才真"杀不掉"
#  Z  ★ 僵尸(已死,等父进程收尸)
#  T  已停止(被 SIGSTOP 暂停)

# === ★ Z 状态:已经死了,kill 无效,要动父进程 ===
# 本文主角。不占 CPU / 内存,只占一个 PID 表项。

# === ★ D 状态:这个才是真正"kill -9 都杀不掉"的活进程 ===
# D = 不可中断睡眠。进程卡在某个【内核操作】里 ——
#   最典型的是【等一个很慢的 IO】(比如 NFS 卡住、
#   磁盘故障)。
# ★ D 状态的进程是【活的】,但它连信号都【暂时无法
#   响应】—— 所以 kill -9 也确实杀不动它,直到那个
#   IO 完成或超时。
$ ps -eo pid,stat,comm | awk '$2 ~ /D/'
# ★ 区别要记牢:
#  - Z 杀不掉,是因为它【已经死了】(动父进程)。
#  - D 杀不掉,是因为它【卡在内核里】(查那个慢 IO)。
#  两者现象像,根因和处理完全不同,别搞混。

# === ★ 孤儿进程:和僵尸是两回事,而且【没有害】 ===
# 孤儿进程 = 父进程先退出了、它自己还活着的子进程。
# 它会被立刻【过继给 1 号进程(init/systemd)】。
# ★ 关键:1 号进程是个尽职的养父,会负责 wait 回收
#   它将来的退出。所以孤儿进程【完全无害】,它有
#   一个靠谱的新爹。
# ★ 别把"孤儿"当问题 —— 真正的问题是"僵尸",是
#   "亲爹还在、却不收尸"。孤儿恰恰是因为爹换成了
#   靠谱的 init,反而没事。

# === 一条命令分清现状 ===
$ ps -eo stat | sort | uniq -c | sort -rn
#   看看 Z 有多少、D 有多少,心里就有数了。

修复 5:正确解法——根治在父进程的代码

# === ★ 解法:现场重启救急,根治在父进程收尸 ===

# === ★ 解法 1:现场救急 —— 重启父进程 ===
# 见修复 3。重启父进程,僵尸过继给 init 被秒收。
$ systemctl restart 那个父服务
$ ps -eo stat | grep -c Z         # 确认归零
# ★ 但这只是"清扫现场"。父进程的代码不改,僵尸
#   还会再长出来。

# === ★ 解法 2:根治 —— 父进程必须 wait() 回收子进程 ===
# 病根永远在父进程的代码:它 fork 了子进程,却忘了
#   在子进程退出后调 wait()。两种正确写法:

# 写法一:专门处理 SIGCHLD 信号,在处理函数里 wait。
#   子进程一退出,内核给父进程发 SIGCHLD,父进程
#   就在这里把尸体收掉:
void on_sigchld(int sig) {
    // ★ while + WNOHANG:一次性把所有已退出的子进程
    //   都收掉(可能同时死了好几个)
    while (waitpid(-1, NULL, WNOHANG) > 0) { }
}
signal(SIGCHLD, on_sigchld);

# 写法二:如果父进程根本不关心子进程的退出状态,
#   可以明确告诉内核"我不收尸了,你直接处理":
signal(SIGCHLD, SIG_IGN);
# ★ 设了 SIG_IGN,子进程退出后内核【不会】生成
#   僵尸,自动清理。适合"fork 完就不管"的场景。

# === ★ 解法 3:各语言里别忘了"收尸" ===
# - Shell 脚本:后台跑了 cmd &,记得在合适的地方
#     wait        # 等所有后台子进程
# - Python:subprocess / os.fork 之后,要
#     p.wait()  或  os.waitpid(pid, 0)
#   用 multiprocessing 时,join() 子进程。
# - 用现成的进程管理器(supervisor、systemd)来拉起
#   服务,它们会负责回收 —— 比自己 fork 省心。

# === ★ 解法 4:容器里要当心 1 号进程 ===
# 容器里,你的应用常常【自己就是 1 号进程】。可一般
#   的应用程序,没有 init 那种"自动收尸"的循环 ——
#   于是容器里的僵尸没人管,会一直堆。
# ★ 解决:给容器加一个轻量 init 作为 1 号进程,
#   由它负责收尸:
$ docker run --init 你的镜像        # ★ --init 注入一个 init
# 或在 Dockerfile 里用 tini 之类作为 ENTRYPOINT。

# === 验证 ===
$ ps -eo stat | grep -c Z          # 现在应长期为 0
$ watch -n5 "ps -eo stat | grep -c Z"   # 盯一会儿,不再增长
# ★ 改了父进程代码、压测一段时间僵尸不再长,才算根治。

修复 6:进程状态排查纪律

# === 这次事故暴露的认知盲区,定几条纪律 ===

# === 1. ★ 僵尸进程(Z / )已经死了,不是活进程 ===
# 它不占 CPU / 内存,只占一个 PID 表项。

# === 2. ★ kill / kill -9 杀不掉僵尸,因为信号是发给活进程的 ===
# 你没法杀死一个已经死了的进程。

# === 3. ★ 僵尸的问题在它父进程 —— 父进程没调 wait() 收尸 ===
$ ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/'   # 看 PPID 找父进程

# === 4. 现场清僵尸:重启父进程,僵尸过继给 init 被秒收 ===

# === 5. ★ 根治:父进程代码里 wait()/waitpid,或 SIGCHLD 设 SIG_IGN ===

# === 6. ★ 别把 D 状态当僵尸:D 是活进程卡在内核 IO 里,真杀不动 ===
$ ps -eo pid,stat,comm | awk '$2 ~ /D/'   # D 状态去查慢 IO

# === 7. 孤儿进程无害,它被过继给 init,有靠谱养父会回收 ===

# === 8. 僵尸虽不占 CPU 内存,但堆积会漏 PID,极端时 fork 不出新进程 ===

# === 9. 容器里应用常是 1 号进程,没收尸能力,用 docker run --init ===

# === 10. 排查"一堆杀不掉的进程"的步骤链 ===
$ ps -eo pid,ppid,stat,comm | sort -k3   # ① 先看状态:Z 还是 D
$ Z -> awk 找 PPID -> 处理父进程          # ② 僵尸:动父进程
$ D -> 查这个进程卡在什么 IO 上           # ③ D 状态:查慢 IO
$ 根治 Z -> 父进程加 wait() 收尸逻辑      # ④ 改代码根治
# 按这个顺序,"杀不掉的进程"基本能分清、能根治。

命令速查

需求                        命令
=============================================================
找所有僵尸进程              ps -ef | grep defunct | grep -v grep
看进程状态和父进程          ps -eo pid,ppid,stat,comm
只挑出 Z 状态进程           ps -eo pid,ppid,stat,comm | awk '$3 ~ /Z/'
统计各状态进程数            ps -eo stat | sort | uniq -c | sort -rn
数僵尸进程个数              ps -eo stat | grep -c Z
找某僵尸的父进程            ps -p  -o pid,stat,comm,args
提醒父进程去收尸            kill -CHLD <父进程PID>
重启父进程清僵尸            systemctl restart <父服务>
看 D 状态进程               ps -eo pid,stat,comm | awk '$2 ~ /D/'
看系统 PID 上限             cat /proc/sys/kernel/pid_max
容器里防僵尸                docker run --init <镜像>

口诀:僵尸已经死了不是活进程,kill -9 杀不掉因为信号是发给活进程的
      问题在父进程没收尸,现场重启父进程过继给 init,根治靠父进程代码 wait()

避坑清单

  1. 僵尸进程 Z 状态带 defunct 已经死了不是活进程,代码停了内存释放了只占一个 PID 表项
  2. 子进程退出后内核保留一个极小的尸体记着退出码,等父进程来取走,这就是僵尸的由来
  3. 父进程调 wait 或 waitpid 取走子进程退出状态后,内核才彻底回收尸体和那个 PID 表项
  4. kill 和 kill -9 杀不掉僵尸,因为信号是发给活进程的,你没法杀死一个已经死了的进程
  5. 僵尸大量堆积长期不消失只有一个原因,它们的父进程没有调 wait 去回收,问题在父进程
  6. 现场清僵尸靠重启父进程,父进程一死僵尸过继给 1 号进程 init,init 会立刻把它们收掉
  7. 根治在父进程代码,处理 SIGCHLD 时 while waitpid 收尸,或不关心退出码就设 SIG_IGN
  8. 别把 D 状态当僵尸,D 是活进程卡在内核不可中断 IO 里真杀不动,要去查那个慢 IO
  9. 孤儿进程和僵尸是两回事且无害,它被过继给 init 有靠谱养父会负责回收它将来的退出
  10. 容器里应用常自己就是 1 号进程没有收尸能力,僵尸会一直堆,用 docker run --init 注入 init

总结

这次"一堆进程连 kill -9 都杀不掉"的事故,纠正了我一个关于"进程"的、特别基础却特别要命的误解。在我的脑子里,凡是能在 ps 列表里出现的东西,就都是一个"进程",而进程,在我的理解里只有两种状态:活着,或者不存在。它要么在运行、占着资源、能被我操作;要么就彻底消失、从列表里清掉。我从来没有想过,在"活着"和"不存在"之间,还存在一个我完全陌生的中间态——一个进程,可以已经死了,却还没有从列表里消失。正因为我脑子里只有这个非黑即白的二元模型,所以当我看到那一串 Z 状态的进程时,我下意识地、不假思索地把它们归进了"活着"那一类——它们明明白白地列在 ps 里嘛。既然它们"活着"、又"有问题",那处理方式就只有一个:杀掉。于是我 kill,我 kill -9,我把我所知道的、最强硬的手段全用上了。而当 kill -9 这个我以为"无坚不摧"的信号也对它们毫无作用时,我感到的是一种认知崩塌般的荒谬:在我的世界观里,就不该存在 kill -9 杀不掉的进程。我把整件事的难点,理解成了"这进程怎么这么顽固"。复盘到根上,我才明白,我从一开始就站错了。kill -9 杀不掉那些僵尸,根本不是因为它们"顽固"、"强大",恰恰相反,是因为它们【太弱了】——弱到已经不存在了。它们早就死了。一个子进程调用 exit() 的那一刻,它的程序代码就停止了执行,它占用的内存、打开的文件,内核当场就回收得干干净净。它已经不是一个能运行、能被调度、能接收信号的实体了。kill 这个命令,我一直望文生义地以为它的意思是"杀死",可它真正做的事,只是"向一个进程发送一个信号"——而信号要起作用,前提是收信的那一方还活着、还有代码在运行、还能对这个信号做出反应。我对着一具尸体发送 SIGKILL,这个信号没有任何活的东西可以承接,它就那样落了空。我之前那个"kill -9 无所不能"的信念,其实暗含了一个我从未察觉的前提:目标必须是活的。对一个死人,再强的"杀"也只是徒劳。那么,僵尸为什么死了却还赖在列表里?因为一个进程的退出,不是它自己一个人的事——它的父进程,可能还想知道"我这个孩子,是正常退出的,还是出错了,退出码是几"。所以内核很贴心地,在子进程死后,替它保留了一具极小的"尸体",里面就记着这么点身后信息,静静地等着父进程来"收尸"——来调用一次 wait(),把这点信息取走。取走的那一刻,内核才会把尸体连同那个 PID 一起,彻底抹去。而我那个服务的悲剧在于:父进程是个不称职的家长,它一个接一个地 fork 出子进程去干活,子进程们尽职地干完、尽职地退出,可这个父进程,从头到尾,没有为它们中的任何一个收过尸。于是尸体越堆越多,堆成了我看到的那一片。这次最大的收获,是我意识到,我那个"非生即死、非有即无"的二元模型,太粗糙了,粗糙到容不下"已死、但尚未被清理"这样一个真实存在的中间状态。而当现实里出现了一个我的模型里没有的状态时,我不但认不出它,还会强行把它塞进我已有的某个类别里——我把一个"死进程"错认成了"顽固的活进程",于是后面所有的努力,方向从一开始就是反的。真正该问的问题,从来不是"我该用多大的力气杀掉它",而是退一步先搞清楚:我眼前这个东西,它现在究竟处于一种什么样的状态?它还活着吗?如果它已经死了,那么能改变现状的,根本不是我对它做什么,而是我去找那个本该为它负责、却失了职的人。所以下一次,当某样东西"怎么弄都弄不动"的时候,我会先停下来,不再加大力气,而是反过来问:它是不是根本就不在我以为的那个状态里?——很多解不开的死结,不是因为结打得太紧,而是因为我一直在拉错的那根绳子。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
Linux教程

df 说磁盘满了 du 却找不到文件:一次 Linux 已删除文件占用空间排查复盘

2026-5-20 21:59:45

Linux教程

服务在 LISTEN 外面就是连不上:一次 Linux firewalld 防火墙排查复盘

2026-5-20 22:07:12

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索