`df -h` 和 `du -sh *` 结果差异大,如何准确判断磁盘空间真实占用?
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
1条回答 默认 最新
蔡恩泽 2026-04-01 21:05关注```html一、现象层:理解 df 与 du 的语义鸿沟
执行
df -h显示根分区使用率 98%,而du -sh * | sort -hr | head -10仅统计出约 65% 的可见目录容量——这并非磁盘损坏,而是典型的“空间幻觉”。df报告的是文件系统级(inode + data block)的已分配块总量,而du统计的是用户态可遍历路径下所有硬链接指向的文件数据块之和。二者视角根本不同:df是内核眼中的“物理占用”,du是 shell 用户眼中的“逻辑可见”。二、机制层:五大核心失配根源深度拆解
序号 原因类别 技术本质 典型场景 验证命令示例 ① 已删除但被进程持有的文件(unlinked but open) 文件 inode 未释放,dentry 已从目录树移除,但 fd 仍指向其 data blocks logrotate 后未重启 nginx;Java 应用持续写入被 rm 的日志 lsof +L1或find /proc/[0-9]*/fd -ls 2>/dev/null | grep deleted② 挂载点遮蔽(mount overlay / bind mount) du默认递归遍历,遇子挂载点即停止(除非加-x),导致底层被覆盖的目录未计入Docker 使用 overlay2;/var/lib/docker/overlay2 下存在巨量隐藏层;/tmp 绑定挂载自 tmpfs mount | grep -E "(overlay|bind|none)"+find / -xdev -type d -name "overlay2" 2>/dev/null③ 文件系统预留空间(filesystem reserved blocks) ext4 默认保留 5% 块供 root 紧急使用( tune2fs -l /dev/sda1 | grep Reserved),df计入但du不体现小容量根分区(如 20GB)上 5% = 1GB,对容量感知影响显著 tune2fs -l /dev/sda1 | grep -i "reserved"或xfs_info /(XFS 无此机制,但有 AG 预分配)三、诊断层:多维穿透式排查工作流
graph TD A[启动排查] --> B{df -h / vs du -shx / 误差 >15%?} B -->|是| C[阶段1:检查 deleted-but-open 文件] C --> D[lsof +L1
或
ls -l /proc/*/fd/ 2>/dev/null | grep deleted] D --> E{发现大量 deleted 文件?} E -->|是| F[定位 PID → lsof -p PID → kill/restart 进程] E -->|否| G[阶段2:检查挂载遮蔽与权限跳过] G --> H[mount -t overlay,bind,xfs,ext4 | grep ' / '] H --> I[find / -xdev -type f -size +100M -print0 2>/dev/null | xargs -0 ls -lhS] I --> J{/var/log/journal 权限是否为 0755?} J -->|否| K[chmod 0755 /var/log/journal && du -shx /var/log/journal]四、进阶层:快照与COW元数据开销不可忽视
ZFS/LVM thin/LXC 容器快照虽不显式存于文件系统层级,但会占用同一 pool/vg 的物理块。例如:
zfs list -t snapshot可能揭示数百 GB 的@autozsys_*快照;lvs -o +seg_monitor,stripes,chunk_size揭示 thin pool 元数据膨胀。XFS 的 reflink 和 ext4 的 project quota 也会引入间接引用开销。此时需运行:xfs_info / && xfs_db -r -c "freesp -s" /dev/sda1对比空闲块一致性。五、工程实践:生产环境黄金排查清单
- ✅ 执行
sudo du -shx --max-depth=1 / 2>/dev/null | sort -hr | head -15(-x跨文件系统限制) - ✅ 运行
sudo lsof +L1 | awk '{sum += $7} END {print "Total deleted-but-open size: " sum/1024/1024 " MB"}' - ✅ 检查 journal 是否失控:
journalctl --disk-usage;若超 2GB,执行journalctl --vacuum-size=500M - ✅ 验证 ext4 预留:
sudo dumpe2fs -h /dev/sda1 | grep -i "block count\|reserved",计算预留块占比 - ✅ 排查 overlay2 层:
sudo du -sh /var/lib/docker/overlay2/* 2>/dev/null | sort -hr | head -5 - ✅ 检查 LVM thin pool:
sudo lvs -o+data_percent,metadata_percent,警惕 metadata 100% 导致写失败 - ✅ XFS 用户空间统计校验:
sudo xfs_info / && sudo xfs_db -r -c "sb 0" -c "print" /dev/sda1 - ✅ 权限盲区扫描:
sudo find / -xdev -type d ! -readable -o ! -executable 2>/dev/null | head -20 - ✅ 内核日志线索:
dmesg -T | grep -i "disk full\|no space\|ENOSPC" - ✅ 最终交叉验证:
sudo debugfs -R "stats" /dev/sda1 2>/dev/null | grep -E "(Free blocks|Block size|Reserved block count)"
六、认知升维:从“找大文件”到“建系统观”
资深工程师不再满足于
```du -sh /var/*,而是构建三层映射模型:① 用户视图(POSIX 路径 + 权限 + 硬链接);② 内核视图(VFS superblock + dentry cache + page cache + block device layer);③ 存储栈视图(LVM/ZFS pool → physical extent → SSD FTLC)。每一次 df-du 差异,都是这三层间语义转换失败的显影。真正的容量治理,始于理解stat()系统调用如何通过generic_fillattr()将磁盘块映射为st_blocks,终于在/proc/mounts与/sys/fs/中完成全栈对齐。本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报- ✅ 执行