做Linux运维的同学,大概率会遇到一个头疼问题:
根目录(/)总容量明明是50GB,但用 du -h / 统计实际文件占用,却只有14GB——足足36GB空间“凭空消失”,df命令显示空间已快占满,但du就是统计不到!
其实这不是空间真的“丢了”,而是两种命令的统计逻辑不同,导致“隐藏占用”未被du识别。先搞懂核心区别,排查起来就很简单了。
先明确2个核心命令的区别(关键!)
第一步:先确认空间差异(必做)
首先执行以下两个命令,精准确认空间占用异常,避免误判:
1. 查看文件系统层面的真实占用
重点看根目录(/)对应的 Used 列,确认是否真的快占满:
[root@test /]# df -hFilesystem Size Used Avail Use% Mounted on/dev/mapper/VolGroup-lv_root 45G 44G 0 100% / # 根目录已占满tmpfs 7.8G 0 7.8G 0% /dev/shm/dev/xvda1 477M 28M 425M 6% /boot
从输出能看到,根目录总容量45G,已用44G,可用为0,确实处于满负载状态。
2. 用root权限统计实际文件占用
用root权限执行du命令,统计根目录所有可见文件的真实占用:
[root@test /]# du -sh /16G /
这里明显出现差异:df显示已用44G,du仅统计到16G,说明有28G空间被“隐藏”占用,大概率是最常见的「已删除文件被进程占用」。
最常见原因:已删除文件被进程占用(90%概率)
核心逻辑:文件被 rm 命令删除后,若有进程仍持有该文件的读写句柄,文件系统会认为这段空间仍被占用(所以df算已用),但du只能遍历“可见文件”,已删除的文件它查不到(所以统计不到)。
第二步:查找占用已删除文件的进程
执行以下命令,精准定位“占用已删除文件”的进程,重点看 SIZE 列(占用空间)和 COMMAND 列(进程名):
sudo lsof | grep deleted | grep -E "/|root"
输出示例(关键信息标注)
java 1234 root 3w REG 253,0 30G 123456 /tmp/bigfile (deleted)nginx 5678 www 4r REG 253,0 5G 789012 /var/log/nginx/access.log (deleted)
解读:
PID:1234(java进程)、5678(nginx进程),是占用空间的核心进程;
SIZE:30G、5G,是对应已删除文件的占用空间;
括号内的 (deleted),表示该文件已被删除,但进程仍在占用。
第三步:释放被占用的空间(2种方法)
找到对应进程后,通过以下两种方法释放空间,优先选更安全的「重启服务」,避免强制杀进程导致异常。
方法1:重启对应服务(推荐,更安全)
如果是nginx、java等服务进程,直接重启服务,会自动释放被占用的文件句柄:
# 示例:重启nginx服务sudo systemctl restart nginx# 示例:重启java服务(根据实际进程名调整)sudo systemctl restart java
方法2:强制杀死进程(紧急情况用)
若服务无法重启(紧急排查),替换 <PID> 为上面查到的进程ID,强制杀死进程(注意:可能导致服务中断,谨慎使用):
# 替换<PID>为实际进程ID(如1234)sudo kill -9 <PID>
最后验证
处理完成后,重新执行以下两个命令,确认空间占用一致,就说明问题解决了:
df -h / # 查看文件系统已用空间du -sh / # 查看实际文件占用空间
总结:遇到df和du统计不一致,优先排查「已删除文件被进程占用」,按照“确认差异→查找进程→释放空间”三步,基本能快速解决问题~