你是否遇到过这种诡异情况?
🔸 df -h 显示磁盘 95% 已用
🔸 du -sh /var/log 却只占 10GB
🔸 明明 rm -f catalina.out 删除了 50GB 日志
🔸 空间却一点没回来!
别慌!
这不是磁盘坏了,也不是文件系统 bug,
而是 有进程还在"偷偷"占用已删除的文件!
今天,手把手教你定位"幽灵进程"、释放空间、彻底根治
1、为什么删了文件,空间却不释放?
在 Linux 中,文件删除 ≠ 空间释放!
关键机制:
bash
文件被删除时,只是移除了目录项(unlink)
只要还有进程打开了这个文件(持有文件描述符),
磁盘空间就不会释放!
直到该进程关闭文件或退出,空间才真正归还。
通俗理解:
就像你借了本书,图书馆把书从书架拿走(rm),但你还没还(进程还在写),书就不能给下一个人用
2、实战:3 步定位"占着茅坑不拉屎"的进程
第一步:确认是否存在"已删除但未释放"的文件
查看被进程打开但已删除的文件(重点关注 deleted)
bash
lsof +L1
正确输出示例:
bash
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 1234 root 1w REG 253,0 52428800 1234567 /app/logs/catalina.out (deleted)
nginx 5678 www-data 5w REG 253,0 1073741824 7654321 /var/log/nginx/access.log (deleted)
重点看:
bash
PID:罪魁祸首进程 ID
SIZE/OFF:占用空间大小(单位:字节)
(deleted):标记文件已被删除但未释放
第二步:根据 PID 查看进程详情
查看进程信息
bash
ps -fp 1234
查看该进程打开的所有文件(验证)
bash
lsof -p 1234 | grep deleted
第三步:释放空间(2 种安全方案)
方案一:优雅重启进程(推荐)
bash
# 例如 Tomcat
./tomcat/bin/shutdown.sh && ./tomcat/bin/startup.sh
例如 Nginx(支持 reload)
bash
nginx -s reload
✅ 优点:服务不中断(Nginx/Logrotate 场景适用)
方案二:强制 kill(慎用)
bash
kill -9 1234
❗ 仅用于无状态进程(如临时脚本、失控 Java 进程)
❌ 切勿用于数据库、核心服务!
🛡️ 如何预防?3 条黄金法则
- 日志轮转必须用 logrotate + copytruncate 或 reload
错误做法:
❌ 千万别这样!
bash
rm -f app.log && touch app.log
正确做法(logrotate 配置):
/var/log/myapp/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate # 适用于无法 reload 的程序(如 Java)
# 或
postrotate
/bin/kill -USR1 `cat /var/run/nginx.pid` # 适用于 Nginx
endscript
}
- Java 应用:避免直接重定向日志到文件
推荐使用 Logback / Log4j2 + 滚动策略,而非:
bash
java -jar app.jar > app.log 2>&1 & # 高危!
- 监控"已删除但未释放"文件
bash
# Prometheus + node_exporter 已支持
node_filesystem_files_deleted
或自定义告警脚本:
if lsof +L1 | grep -q deleted; then
echo "ALERT: Deleted files still held by processes!" | mail -s "Disk Leak" admin@example.com
fi
快速自查清单
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| df 和 du 结果相差巨大 | 有进程占用已删文件 | lsof +L1 定位 |
| 删除日志后磁盘仍满 | 应用未关闭文件描述符 | 重启或 reload 进程 |
| 空间突然释放 | 进程意外退出 | 检查是否异常崩溃 |
写在最后
在 Linux 里,文件的生命,由进程说了算。
删除只是开始,释放才是终点。
掌握 lsof +L1,
你就能在磁盘"消失"的迷雾中,
一眼看穿真相!