当前位置:首页>Linux>Linux 删了文件磁盘空间却没释放?一文搞定 df 与 du “打架”

Linux 删了文件磁盘空间却没释放?一文搞定 df 与 du “打架”

  • 2026-09-30 19:33:08
Linux 删了文件磁盘空间却没释放?一文搞定 df 与 du “打架”

明明删了几个 G 的日志,df -h 一看磁盘还是 100%?用 du -sh 检查目录,却发现实际占用并不高……

别慌。这种现象在运维中很常见 —— 文件已经删了,但磁盘空间没释放。今天我们就从原因、排查到解决,把这事彻底讲明白,顺便帮你弄懂 df 和 du 为什么总“打架”。


一、现象重现:删了文件,空间却没回来

假设你遇到下面这种情况:

    # 查看磁盘使用率,/var 分区已经 100%$ df -h /varFilesystem      Size  Used Avail Use% Mounted on/dev/sda3  20G20G0100% /var# 查看 /var/log 目录实际大小,只有 2G$ du -sh /var/log2.0G    /var/log# 刚才明明删了一个 15G 的日志文件 app.log$ rm -f /var/log/app.log

    矛盾出现了:

    • df 说分区还用了 20G(满的)
    • du 说 /var/log 只有 2G
    • 那“丢失”的 18G 去哪了?

    答案:有一个进程还在“抱着”那个已经删掉的文件不放手。


    二、为什么会出现这种情况?

    1. Linux 删除文件的真实过程

    在 Linux 中,一个文件由两部分组成:

    • 数据块:真正存储内容的磁盘区域
    • 目录项:文件名与数据块的“映射”

    执行 rm 时,只是从目录中删除了这个映射。如果此时没有任何进程打开这个文件,内核才会真正回收数据块。但如果有进程正在使用这个文件(比如一直在写日志),即使目录项没了,进程仍然保留着文件的“通行证”(文件句柄)。于是:

    • 目录里已经看不到这个文件了
    • 但磁盘上的数据块仍然被占用,不能释放

    这些“无名”的文件,很多运维朋友叫它 幽灵文件。

    2. 哪些场景容易踩坑?

    • 应用直接写日志(比如 Java、Tomcat、Nginx),你直接 rm 删了日志文件
    • 数据库长时间运行,你删了它的数据文件或临时文件
    • 你在一个打开的文件上执行了 rm,却没先停掉服务

    三、df 与 du 的“矛盾”本质

    1. 它们到底怎么统计的?

    命令
    信息来源
    统计逻辑
    会不会统计幽灵文件
    df
    文件系统的超级块
    整个分区的“已用块”总数
    ✅ 会统计
    du
    对每个文件调用 stat()
    累加目录下可见文件的大小
    ❌ 不统计

    2. 为什么结果不一样?

    • df 直接读文件系统元数据 → 分区用了多少块,它就报多少(包括幽灵文件)
    • du 只能看到当前目录里“还存在”的文件 → 看不到已从目录删除的文件

    所以当幽灵文件出现时:

    df 看到的:分区占用 = 正常文件 + 幽灵文件du 看到的:分区占用 = 正常文件(幽灵文件不可见)

    结果就是 df 显示使用量明显大于 du。

    顺便说一句,即使没有幽灵文件,df 和 du 也可能有少量差异(比如文件系统预留空间、元数据开销),但正常差异一般不超过 5%。如果差了好几个 G,基本就是幽灵文件没跑了。


    四、如何定位“幽灵文件”?

    1. 快速检查

    执行下面这条命令:

    lsof | grep deleted

    输出类似这样:

    java  1234root5wREG8,315360000123456/var/log/app.log (deleted)

    信息解读:

    • java:进程名
    • 1234:进程 PID
    • 5w:文件描述符(w 表示写入)
    • /var/log/app.log (deleted):原文件路径,括号里的 deleted 说明它已被删除但未释放

    如果屏幕上刷出一堆这样的记录,那元凶就找到了。

    2. 更精确的过滤(只看真正占空间的)

    lsof +L1 | grep deleted

    +L1 会筛选出链接数为 0 但仍被打开的文件,命中率更高。


    五、如何释放空间?(3 种方法)

    ✅ 方法一:杀掉占用进程(最直接)

    kill -9 <PID>

    优点:空间瞬间释放缺点:会中断业务,需要评估影响

    比如上面查到 PID=1234,执行 kill -9 1234 后,磁盘空间就回来了。

    ✅ 方法二:清空文件内容(生产环境推荐)

    如果你不想杀进程,可以清空文件内容,而不删除文件本身。

    先找到文件描述符(FD):

    ls -l /proc/1234/fd/ | grep deleted

    输出示例:

    lrwx------ 1 root root 64 ... 5 -> /var/log/app.log (deleted)

    其中 5 就是文件描述符编号。然后清空它:

    echo"" > /proc/1234/fd/5

    或者用 truncate:

    truncate -s 0 /proc/1234/fd/5

    效果:文件内容被清空,进程继续运行,磁盘空间立刻释放。很适合不能重启服务的场景(比如核心数据库、在线业务)。

    ✅ 方法三:重启服务或服务器

    • 重启持有该文件句柄的服务(如 systemctl restart nginx)
    • 最后手段:重启整台服务器(慎重,适合测试环境或实在没招的时候)

    六、怎么预防?别让问题再发生

    措施
    具体做法
    不要直接 rm 正在被写的文件
    改用 echo "" > file 或 truncate -s 0 file 清空
    使用 logrotate
    配置 copytruncate 选项,先拷贝再清空,进程不中断
    定期监控
    写个 crontab,每天执行 lsof +L1 | grep deleted,有异常就告警
    养成好习惯
    删大文件前,先用 lsof 看看有没有进程在用

    七、总结

    • 现象:rm 删了文件,df 显示空间没释放,du 显示已释放 → 大概率是幽灵文件
    • 原因:仍有进程持有该文件的句柄
    • 排查:lsof | grep deleted
    • 解决:kill 进程 或 清空 /proc/PID/fd/FD
    • 预防:不直接 rm 正在写的文件,用 logrotate + copytruncate

    记住一句话:

    在 Linux 世界里,文件是否真的“消失”,不光看目录,还要看有没有进程还“抱着”它。

    最新文章

    随机文章