答案是已删除但仍被进程占用的文件(unlinked but open),因inode未释放导致df统计占用而du不可见;需用lsof +L1定位,再通过reload、kill或docker restart安全释放空间。

磁盘空间显示已满,但 du 扫不出对应大文件——八成是“已删未释放”的残留文件在占着空间,不是没清理,是根本没释放。
为什么 df 和 du 结果对不上?
这是最典型的残留文件信号:df -h 显示根目录用了 95%,但 du -sh /* 2>/dev/null | sort -hr 加起来才 60%。差额那部分,大概率就是被进程打开后又 rm 掉的文件——路径没了,inode 还挂着,空间卡死不还。
-
du只统计当前文件系统里“有路径可查”的文件,(deleted)的东西它看不见 -
df统计的是底层 block 占用,不管路径存不存在,只要 inode 没释放就算 - 常见于日志服务(
rsyslog、nginx)、Java 应用、Docker 容器内进程持续写日志后又被 logrotate 删除
用 lsof +L1 快速揪出残留文件
执行 sudo lsof +L1 是最直接的办法,它专找 link count 为 0 的文件(即已被 unlink() 但 fd 仍开着)。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 输出中
NAME列带(deleted)后缀的就是目标,比如/var/log/app.log (deleted) - 重点关注
PID和COMMAND,确认是不是关键服务(别见java就杀) - 如果只查某挂载点,加路径过滤:
sudo lsof +L1 /var - 旧版
lsof不支持+L1?用sudo lsof | grep 'deleted$'替代,但速度慢、噪音多
确认残留文件实际大小
光看 lsof 输出里的 (deleted) 不知道占多少空间,得查进程 fd:
- 用
sudo ls -lh /proc/<pid>/fd/ | grep deleted</pid>,注意单位(有些显示0B但实际占 GB) - 更准的方式:
sudo du -sh /proc/<pid>/fd/* 2>/dev/null | grep -v 'No such file'</pid> - 别尝试
echo > /proc/<pid>/fd/<fd></fd></pid>清空——这会往原数据块写零,不释放空间,还可能破坏残留内容
安全释放空间的三种方式
释放的关键是让进程关闭 fd,而不是硬删文件本身:
- 若进程支持平滑重载(如
nginx、rsyslog),优先发kill -HUP <pid></pid>,让它重新打开日志文件 - 确认该进程非核心服务(比如测试环境的
java进程),再kill <pid></pid> - 如果是 Docker 容器内进程,
docker restart <container_id></container_id>比直接 kill 宿主机进程更稳妥 - 切忌盲目
systemctl restart整个服务——某些服务重启会丢状态或触发重建,反而扩大影响
真正难的不是找到残留文件,而是判断哪个 (deleted) 是该留的(比如 logrotate 配了 copytruncate)、哪个是该放的。盯着 PID 查 ps -fp <pid></pid> 或 systemctl status 对应服务,比瞎猜靠谱得多。

















