文件已删除但空间未释放
发布时间:2026-07-11 20:32       
更新时间:2026-07-12 15:37
删掉的日志文件足足 5GB,磁盘占用却一格未降——问题不在 rm,而是还有进程握着这个文件的句柄。
## 原理:删除只是摘掉名字
Linux 里删除文件实际是减少它的硬链接计数,目录里的名字没了,但文件数据要等所有打开它的进程关闭句柄后才被真正回收。日志类文件最典型:rm 完之后,写日志的守护进程手里还拿着旧句柄,继续往一块"看不见的文件"里写,空间照常增长。
这个机制也有它的用途:正在写的文件不怕被误删,进程能继续工作到自然结束,代价只是空间回收延后。
## 用 lsof 找到占用进程
lsof +L1
lsof 是查看进程打开文件的工具,+L1 列出链接数小于 1(已删除但仍在打开)的文件,FD 列带 w 的就是还在写的进程,PID 和进程名一目了然。从全量输出里筛也可以:lsof | grep deleted。精简系统没有 lsof 时,find /proc/*/fd -ls 2>/dev/null | grep deleted 也能达到同样效果,输出朴素些而已。
## 两条处理路径
不停服务的做法:通过 /proc 找到该进程持有文件的描述符,把大文件直接清零(root 身份执行)。假如 PID 是 1234、FD 是 4:
echo > /proc/1234/fd/4
空间立刻释放,进程无感知。更彻底的做法是重启对应服务:systemctl restart nginx 之类的操作会关闭全部旧句柄,空间随之归还。挑业务低峰执行,重启前想清楚该服务是否允许中断。有的进程被守护工具托管,重启入口要找对,盲目 kill 会立刻被拉起,等于白做。echo 清零法只对仍被打开的文件有意义,普通已关闭文件直接 rm 即可,别把简单问题复杂化。
## 以后用轮转代替手工 rm
规范的日志管理交给 logrotate,配置里加 copytruncate 选项,切割时先复制再原地清空,全程不需要服务重载句柄,从机制上杜绝"删了不释放"。它的 size 条件与时间条件可以并用,日志暴涨的日子按体积分割更及时,纯按天切可能失控。日常遇到磁盘异常,df 和 lsof 两个工具先后出手,这类问题三分钟内见分晓。