Linux 怎么查看磁盘空间?df、du 与文件删除但空间不释放
答案:分区层面 df -h 看使用率,目录层面 du -h -d1 <路径> | sort -rh 找大头。两者对不上时,多半是"文件已删但进程还持有句柄",用 lsof | grep deleted 定位。
一、df:看分区还剩多少
df -h # 人类可读单位(GB/MB)
df -h /var # 只看某路径所在分区
df -i # 看 inode 使用率(小文件爆满时关键)
df -T # 顺带显示文件系统类型| 列 | 含义 |
|---|---|
Size / Avail | 总量 / 普通用户可用 |
Use% | 使用率,到 90%+ 要警惕 |
Mounted on | 挂载点(容器里常见 overlay) |
二、du:找是哪个目录占的
du -sh /var/* # /var 下每个条目总大小
du -h -d1 / | sort -rh # 根分区一级目录,按大小降序(最实用)
du -ah /data | sort -rh | head -n 20 # 列出最大的 20 个文件/目录
ncdu / # 交互式浏览,装了最方便
-d1(或老写法--max-depth=1)只展开一层,避免一上来扫全盘;先在根目录定位到/var、/data这类大头,再一层层下钻。大文件通常在日志、数据库、容器镜像/数据卷、core dump。
三、df 满但 du 对不上:被删除文件仍占用
这是最经典的坑:
df -h # 显示 / 已用 95%
du -sh /* # 加起来却远小于已用量
# 找已被删除但仍被进程持有的文件:
sudo lsof +L1 | grep deleted
# java 1234 root 5w REG ... 1234567890 /data/app.log (deleted)
rm只删目录项,只要还有进程打开着这个文件,inode 和数据块就不释放。常见于被rm的日志文件、其进程(Java/nginx/数据库)还在写。处理:
- 能重启服务就重启,句柄关闭即释放;
- 不想重启,且文件仍以写入方式打开,可清空其句柄(如
: > /proc/<pid>/fd/<n>)让其截断;- 最稳的是以后用
truncate/logrotate,而不是rm活跃日志。
四、有空间却写不进:inode 用尽
df -i # IUse% 100% 但 Use% 不高 → inode 耗尽
# 通常是某个目录堆了几百万个小文件(缓存、session、邮件队列)
for d in /var/*; do echo "$(ls -a $d 2>/dev/null | wc -l) $d"; done | sort -rn | head一个文件占一个 inode,海量小文件会在磁盘没满时先把 inode 耗尽,同样报
No space left on device。解决办法是清理或合并小文件(如按天分桶)。
五、日志撑爆的正确应急
: > /var/log/app.log # 清空但保留 inode,正在写的进程不受影响(推荐)
truncate -s0 /var/log/app.log # 等价
logrotate -f /etc/logrotate.conf # 强制按策略轮转
# 不要:rm 一个正在被写入的日志(空间不释放,且新日志可能写到已删 inode)长期治理靠 logrotate(按大小/天数轮转、压缩、保留份数)和应用层日志级别控制。容器场景还要记得清
docker system prune堆积的镜像层与悬空卷(见 docker)。
FAQ
Q: 怎么看磁盘剩余? A: df -h 看分区使用率,df -i 看 inode;定位目录用 du -h -d1 / | sort -rh。
Q: df 满但 du 少? A: 已删除文件仍被进程持有句柄,lsof +L1 | grep deleted 找出来,重启或截断其 fd 后释放。
Q: 有空间却 No space left? A: 多半 inode 用尽,df -i 确认,清理海量小文件目录。
Q: 怎么找最大文件? A: du -ah 路径 | sort -rh | head 或交互式 ncdu。
Q: 日志写满怎么处理? A: 用 : > app.log/truncate -s0 清空保留 inode,或 logrotate 轮转;别直接 rm 活跃日志。
一句话总结:df -h 看分区、du -h -d1|sort -rh 找大目录;df 与 du 对不上先查 lsof | grep deleted(删了但进程还持有);写不进但有空间查 df -i 是否 inode 耗尽;清活跃日志用 truncate/logrotate 而不是 rm。