Linux 磁盘满了却找不到大文件:从 df、du 查到打开的删除文件
删除一个大日志后,df 的可用空间却没有增加,继续删其他文件通常不是好主意。文件名消失与存储空间释放不是同一件事。本文针对 Linux 本地文件系统,使用 GNU coreutils 9.x 与 lsof 的常用选项;网络文件系统、容器挂载和写时复制文件系统需要额外结合其实现判断。所有排查命令以只读观察为主。
AI生成概念配图:已删除的文件仍被运行进程持有,磁盘空间暂未释放。仅辅助理解,不代表真实界面或实测结果。
先确认满的是哪个资源
df -hT /var df -i /var sudo du -x -h --max-depth=1 /var
df 查看包含指定路径的整个文件系统,du 沿目录树统计可见文件。如果 /var 只是根文件系统中的一个子目录,就不能直接拿它的 du 总数与整块根文件系统比较。先看挂载点,再把扫描范围对齐。-x 避免跨入其他文件系统;权限不足造成的漏扫也必须记录,不能把报错后的结果当成完整总量。
df -i 用来检查 inode。大量小文件可能耗尽 inode,即使容量仍有剩余也会影响新文件创建。遇到这种情况,应找出哪个目录在持续生成对象,按应用的保留策略处理,而不是只寻找体积最大的文件。扫描大型目录会产生 I/O 开销,繁忙主机上应控制范围和时机。
理解 df 与 du 为什么不相等
df 反映文件系统整体统计,du 反映目录层级里的占用估计。文件系统元数据、保留空间、快照或共享数据块等因素都可能带来差异;稀疏文件的逻辑长度也不等于实际分配空间。因此差值只能作为线索,不能直接解释成“有隐藏垃圾”。不要为了让两个数字一致而强行清理系统目录。
特别常见的一种情况是:进程已经打开日志,维护者删除了目录项,但进程仍持有该文件并继续写入。此时路径遍历看不到它,文件内容占用却仍存在。空间通常要等相关打开引用释放后才能回收;仅创建一个同名新文件,也不会让旧句柄自动切换过去。
找出仍被持有的删除文件
sudo lsof -nP +L1 # 若 /var 是实际挂载点,可限定该文件系统 sudo lsof -nP -a +L1 /var
+L1 选择链接数小于一的打开文件。重点查看进程名、PID、FD、设备、节点和大小相关列,再确认它们是否属于正在告警的文件系统。同一文件可能被多个描述符或进程持有,不能把每一行的大小简单相加。lsof 的可见范围还受权限、内核与命名空间影响,空结果不等于已经排除所有可能。
释放前先确定服务的正确动作
确认进程身份后,优先采用该服务官方支持的日志重新打开或轮转方式。不同程序的信号语义不同,不要看到网上的 kill 命令就照搬;信号发错可能直接终止业务。若只能通过重启释放,应先评估连接、队列和写入状态,安排允许的维护窗口。生产数据库与业务数据文件尤其不能按日志思路处理。
不要直接向 /proc/进程号/fd/描述符 重定向空内容。那相当于改写进程正在使用的文件,可能破坏数据或让程序处于未预期状态。也不要用 kill -9 当作通用磁盘清理方案。排障需要的是找出持有者和正确生命周期,而不是绕过应用把文件强制抹掉。
最后验证空间和根因都已改善
执行经过确认的恢复动作后,再检查 lsof、df 和服务日志,确认旧引用消失、可用空间变化、应用仍能正常写入。若容量没有恢复,就继续核对快照、挂载覆盖或统计范围等因素。最后修正日志轮转、保留周期与告警阈值,记录产生速度;只恢复一次空间而不控制增长,故障还会回来。


