文件删了空间没释放:被占用的句柄
发布时间:2026-09-29 14:47       
更新时间:2026-09-30 12:11
rm 之后 df 显示占用纹丝不动,这不是文件系统出了故障,而是那个文件还被某个进程握在手里。
为什么会这样
Linux 删除文件只是把目录项摘掉,空间要等文件的打开计数降为零才真正释放。某个进程(常见的是 nginx 或应用)还打开着一个 10G 的日志文件,你把它 rm 掉,目录里确实看不见了,但 inode 和数据块仍被进程占用,空间照样不还给你。这个设计本意是保护正在进行的读写——文件被删,正在用它的进程不受影响;代价就是空间回收要等句柄关闭。这个计数由内核维护,进程退出或正常关闭文件,计数才会减一,没有捷径。这就是"删了最大的文件,磁盘却没变多"的由来。
怎么确认
lsof | grep deleted
输出会列出进程名、PID 和带 deleted 标记的文件路径。按 SIZE 排序找最大的,看它属于哪个进程,基本就能对上号。binlog 和日志目录里这类情况最集中,处理前先认清握句柄的是哪个服务,别误伤。没有装 lsof 的系统,翻 /proc/*/fd 也能查,但 lsof 最直观,yum 或 apt 装一个不费事。
两种处理方式
原则是让进程把句柄放掉,或者让文件变小,而不是再删一遍。
方法一,重启握着句柄的进程,比如 systemctl restart nginx。干净利落,但会有几秒中断,要挑时间执行。
方法二,不重启就清空文件内容,句柄不变、空间立即释放:
: > /var/log/nginx/access.log
也可以通过 /proc 找到句柄直接操作:ls -l /proc/进程PID/fd | grep deleted 找到对应编号,执行 : > /proc/进程PID/fd/编号 同样有效。
怎么预防
清理大文件养成用 truncate -s 0 文件名 的习惯;logrotate 配置里对不能中断的服务加 copytruncate 选项,轮转时先复制再清空原文件,绕开句柄问题;删文件前先过一遍 lsof,确认没人握着再动手;再把"先 truncate 再删"写进团队的运维手册,比记在脑子里可靠。
一句话总结:空间没释放,说明有人还没放手。先找到那个进程,再决定是让它重启还是就地清空。