首页 / 内容指南 / 当前文章

Linux删除大文件后磁盘空间没释放:lsof、进程句柄与Journal清理检查清单

发布于 2026-08-26 · Content Fleet 编辑部

先用 df -hT 确定真正满的文件系统,再在同一挂载点比较 du -x。运行 lsof +L1 查找链接数小于 1 的已删除打开文件,重点查看进程、PID、FD、文件大小和路径。优先让对应服务正常重新打开日志,例如使用受支持的 reload、日志轮转或有序重启;不要直接操作 /proc/PID/fd 截断生产文件,除非已经确认写入语义、备份与回滚。若占用来自 systemd journal,先查看 journalctl --disk-usage,必要时 rotate 后清理归档日志,并配置长期上限。

直接答案

先用 df -hT 确定真正满的文件系统,再在同一挂载点比较 du -x。运行 lsof +L1 查找链接数小于 1 的已删除打开文件,重点查看进程、PID、FD、文件大小和路径。优先让对应服务正常重新打开日志,例如使用受支持的 reload、日志轮转或有序重启;不要直接操作 /proc/PID/fd 截断生产文件,除非已经确认写入语义、备份与回滚。若占用来自 systemd journal,先查看 journalctl --disk-usage,必要时 rotate 后清理归档日志,并配置长期上限。

一、先确认哪个文件系统已满

df 统计文件系统块使用情况,du 统计从目录树仍可遍历到的文件。容器 overlay、独立 /var、挂载卷和 bind mount 可能让路径看起来相同,却属于不同文件系统。先记录设备、类型、挂载点、总量、已用和可用空间。

使用 du -x 限制在目标文件系统内,避免跨入其他挂载点。不要一开始就在根目录执行高并发全盘扫描,生产主机上应限制范围和 I/O 优先级。

二、为什么rm后空间还在

rm 删除的是目录中的名字,本质上调用 unlink。若进程此前打开了该文件,内核中的打开文件描述仍然有效,进程可以继续写入。此时 du 无法通过原路径看到文件,但 df 仍统计其数据块。

这常发生在应用、Nginx、数据库或日志代理持续写日志,而管理员直接删除当前日志文件。正确日志轮转应通知进程重新打开文件,或使用应用支持的轮转机制。

三、使用lsof +L1定位

lsof 手册说明,+L1 选择仍被打开但链接计数小于 1 的文件。常用检查为:

sudo lsof +L1

输出中关注 COMMAND、PID、USER、FD、SIZE/OFF 和 NAME。若系统文件很多,可按目标文件系统、进程或路径进一步过滤。非 root 用户可能看不到其他用户进程的全部文件,因此“没有输出”不一定证明不存在。

四、安全释放空间

最稳妥的方法是让持有文件的进程关闭旧描述符。先确认服务名称、流量、可用副本和重启影响;如果应用支持重新打开日志的信号或 reload,应使用官方方式。否则在负载均衡中逐实例摘流、重启并验证。

不要直接 kill -9 关键进程。强杀可能中断事务、损坏临时状态或触发同时重启。也不要盲目向 /proc/PID/fd/N 写空内容,进程的当前偏移、追加模式和日志库行为可能造成稀疏文件或后续异常。

五、验证空间真正回收

服务关闭旧句柄后,重新运行 lsof +L1,确认目标记录消失,再检查 df -hT。同时观察服务状态、错误日志、监听端口和关键请求。

若空间没有变化,检查是否还有其他 PID、容器中的进程或同一文件系统上的删除文件。容器宿主机和容器命名空间可能看到不同进程视图,需要在正确环境中诊断。

六、systemd Journal占用

使用 journalctl --disk-usage 查看 active 与 archived journal 文件的总占用。官方文档说明,--vacuum-size--vacuum-time--vacuum-files 只清理归档文件,活动日志不会被直接 vacuum。

需要立即压缩历史时,可评估先 rotate 再 vacuum,但要遵守日志保留、审计和故障取证要求。清理前保存必要事件,不要在事故调查中无备份删除唯一证据。

七、配置长期Journal上限

journald.conf 中可使用 SystemMaxUseSystemKeepFreeRuntimeMaxUse 等控制持久或运行时日志空间。配置后验证实际存储位置是 /var/log/journal 还是 /run/log/journal,并记录变更与回滚。

上限不是替代日志治理。持续日志风暴应修复产生源、重复堆栈和错误重试,否则清理只会暂时恢复空间。

八、du与df差异的其他原因

已删除打开文件不是唯一原因。还要检查文件系统保留块、inode 耗尽、快照、稀疏文件、硬链接、容器层和文件系统元数据。df -i 可检查 inode;大量小文件可能在容量尚有剩余时先耗尽 inode。

硬链接文件只有所有目录链接都删除后链接计数才归零。快照和存储系统的回收规则也可能让宿主机工具看到不同结果,应使用对应平台工具验证。

九、日志轮转为什么会失败

常见错误是轮转脚本把当前文件 rename 或删除,却没有通知应用重新打开;应用继续写旧 inode,新文件存在但没有内容。另一个风险是 copytruncate 在复制与截断之间可能丢失少量日志,并不适合所有高价值审计场景。

优先使用应用原生滚动或 rotate 后明确 reopen。验证应包括旧句柄关闭、新文件持续增长、权限与 owner 正确,以及日志采集器跟随了新文件。

十、生产处置顺序

1. 保存 dfdu、inode 和挂载信息。

2. 找出 lsof +L1 中最大记录。

3. 将 PID 映射到服务、容器和负责人。

4. 确认备份、流量切换与重启影响。

5. 正常 reload 或逐实例重启。

6. 验证描述符关闭、空间回收和服务健康。

7. 检查 journal、快照和其他差异来源。

8. 修复日志轮转和容量告警。

十一、常见错误

  • 看到磁盘满就递归删除未知目录。
  • 删除当前日志但不让进程重新打开。
  • 只看du,不看df与挂载点。
  • 直接kill关键数据库进程。
  • 在事故取证前清空journal。
  • 把vacuum当作永久解决日志风暴。
  • 忽略容器命名空间与宿主机差异。
  • 没有验证新日志文件继续写入。

十二、FAQ

重启服务器一定会释放吗?

通常会关闭所有进程描述符,但代价很高,也可能掩盖根因。优先识别单个服务并有序处理。

lsof没有结果为什么df仍然满?

可能权限不足、检查了错误命名空间,或根因是快照、保留块、inode、硬链接和文件系统元数据,而不是删除文件。

可以直接截断/proc/PID/fd中的文件吗?

风险较高。可能影响偏移和写入语义;除非已确认应用行为并具备回滚,否则应让进程正常关闭或重新打开。

journalctl vacuum后为什么占用仍然较大?

vacuum主要删除归档journal,活动文件仍被统计。可结合rotate,并检查长期上限和日志产生速率。

十三、总结

删除文件后空间不释放,本质上是“路径已消失,但数据仍被打开引用”。先用挂载点、df与du确认范围,再用 lsof +L1 找到持有者,通过正常 reopen、reload 或逐实例重启关闭句柄。Journal、inode、快照和容器层要单独验证,最后修复轮转和容量策略,避免同类故障复发。

官方参考资料

  • Linux man-pages:lsof(8),https://man7.org/linux/man-pages/man8/lsof.8.html(核验日期:2026-08-29)
  • systemd:journalctl,https://www.freedesktop.org/software/systemd/man/latest/journalctl.html(核验日期:2026-08-29)
  • systemd:journald.conf,https://www.freedesktop.org/software/systemd/man/latest/journald.conf.html(核验日期:2026-08-29)