空间未释放主因是进程仍占用已删文件,核心命令为lsof +l1精准定位链接数为0的“幽灵文件”,输出中name列含(deleted)即确认,结合pid和fd可安全清空或重启对应进程。

直接结论:空间没释放,95%是因为还有进程在用那个文件,不是磁盘坏了,也不是rm失灵,更不需要重启机器。
怎么快速定位“已删但占空间”的文件
核心命令是 lsof +L1,它只列出链接数为 0 的打开文件——也就是目录项没了、但进程还在读写的“幽灵文件”。
-
+L1比lsof | grep deleted更准,后者可能漏掉没打括号标记的条目(比如某些内核版本或容器环境) - 输出中
(deleted)出现在NAME列末尾才是关键信号,如:/var/log/nginx/access.log (deleted) - 重点关注
PID和FD列:PID 是占用进程号,FD 是它打开该文件用的描述符编号,后续操作都靠这两个值 - 如果系统没装
lsof,可用find /proc/[0-9]*/fd -ls 2>/dev/null | grep deleted替代,但输出更难读
为什么 df 和 du 看到的空间不一致
df 统计的是文件系统级实际占用块,du 统计的是目录树下“可见文件”的大小。当文件被 rm 但进程未释放时,df 还得算那块空间,du 却找不到对应路径,所以两者差值≈那些 (deleted) 文件的总大小。
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
- 执行
du -sh / && df -h /对比,差值大于几 MB 就值得怀疑有残留句柄 - 注意:
du不会扫描/proc下的 fd 符号链接,所以永远看不到被删文件的大小 - 某些日志轮转工具(如
logrotate配了copytruncate)也会导致类似现象,但本质仍是进程持续写入原文件句柄
kill 进程前必须确认的三件事
别一看到 PID 就 kill -9,尤其在线上服务里,容易引发数据丢失或状态不一致。
- 先看
COMMAND和USER列,确认是不是关键服务:比如mysqld、java、nginx—— 杀错可能整个业务中断 - 查进程当前工作目录和打开文件详情:
ls -l /proc/<code>PID/cwd 和ls -l /proc/<code>PID/fd/ | grep deleted - 优先尝试优雅重启服务:
systemctl reload nginx或kill -USR1 <code>PID(对支持重载日志的进程),比强制 kill 更安全 - 实在不能停服务?可在线清空:
echo > /proc/<code>PID/fd/FD(例如echo > /proc/1234/fd/15),这会让内核立即释放底层 block,且进程通常无感知(仅对可写文件有效)
容易被忽略的隐藏坑
有些情况 lsof +L1 压根不显示,但空间就是不释放——这时候要往更深一层想。
- 容器环境:宿主机上
lsof看不到容器内进程打开的已删文件,得进容器 namespace 查,或用nsenter -t <code>PID-n lsof +L1 - 挂载覆盖:如果删的是挂载点下的文件,而该挂载点又被 bind mount 覆盖过,
df统计的是上层挂载,lsof可能指向底层设备,需用findmnt核对真实挂载位置 - ext4 的 delayed allocation:极少数大文件写入中被删,内核可能延迟回收元数据,等几十秒再
df一次,有时空间就回来了——但这种情况极少,别当成首选解释
真正麻烦的从来不是“找不到谁占着”,而是“找到之后不敢动”。盯住 PID 和 FD,搞清进程用途,再决定是 reload、kill 还是清空 fd,比盲目重启靠谱得多。










