df 顯示磁盤滿了,但 du -sh * 統計目錄大小總和卻遠小於已用空間——這是經典的「磁盤空間失蹤」現象。本文深度解析三大核心成因:隱藏文件統計遺漏、掛載點遮蓋原有數據、已刪除文件被進程持有(稀疏/洞文件),並提供一鍵排查腳本與預防措施。
# df 顯示 /var 分區 95% 已用
df -h /var
# Filesystem Size Used Avail Use% Mounted on
# /dev/sda3 100G 95G 5.0G 95% /var
# du 統計卻只有 60G
du -sh /var/*
# 60G 總和
# 差額 35G 去哪了?
核心認知:df統計**文件系統分配的塊**(含已刪除但未釋放的塊),du統計**目錄樹下可見文件的塊**。兩者統計口徑不同,差異即為「幽靈佔用」。
du -sh * 的通配符 * **不匹配以點開頭的隱藏文件/目錄**(如 .git、.cache、.npm、.docker)。
# 正確統計:包含隱藏項
du -sh /var/.[^.]* /var/* 2>/dev/null | sort -hr
# 或使用 --apparent-size 顯示表觀大小
du -sh --apparent-size /var
# 找出大隱藏目錄
find /var -maxdepth 2 -type d -name '.*' -exec du -sh {} \; 2>/dev/null | sort -hr | head
/var/cache/、/var/tmp/:安全清理/root/.cache/、/home/*/.cache/:用戶緩存,可清/.snapshots/ (Snapper/Btrfs):快照佔用,按策略清理將新分區掛載到**非空目錄**上,原目錄下的文件被「遮蓋」,du 見不到,但磁盤塊仍被佔用(因 inode 仍被引用)。
# 1. 找出所有掛載點
findmnt -T /var
# 或
mount | grep /var
# 2. 檢查掛載點原目錄殘留數據
# 臨時掛載到別處查看
mkdir /tmp/var_orig
mount --bind / /tmp/var_orig
du -sh /tmp/var_orig/var # 這裡能看到被遮蓋的數據
umount /tmp/var_orig
進程打開文件寫入 → 文件被 rm 刪除(目錄項移除,inode 連接數歸零但>0) → 進程繼續寫入 → 數據寫入「無名」塊 → df 計入已用,du 遍歷不到 → 空間「失蹤」。
# 1. lsof 找出已刪除但被持有的文件
lsof -nP | grep deleted
# 輸出示例:
# java 1234 user 100u REG 253,0 10737418240 12 /var/log/app.log (deleted)
# 關鍵列:PID、FD、SIZE、PATH
# 2. 統計此類佔用總大小
lsof -nP | grep deleted | awk '{sum+=$7} END {print sum/1024/1024 " MB"}'
# 方法 1:通過 /proc 截斷文件(推薦,進程繼續運行)
# FD=100, PID=1234
: > /proc/1234/fd/100
# 文件大小歸零,空間即時釋放,進程可繼續寫入
# 方法 2:發送信號觸發日誌輪轉(如 logrotate 配置)
kill -USR1 1234 # 視應用支持而定
# 方法 3:重啟進程(終極方案)
systemctl restart app-service
#!/bin/bash
# /usr/local/bin/find_lost_space.sh
# 輸出:三大類失蹤空間的詳細清單
TARGET="${1:-/}"
echo "=== Lost Space Analysis for $TARGET ==="
echo "Timestamp: $(date)"
echo ""
echo "--- 1. Hidden files/dirs (du misses) ---"
du -sh ${TARGET}/.[^.]* ${TARGET}/* 2>/dev/null | sort -hr | head -20
echo -e "\n--- 2. Mount point masking ---"
findmnt -T "$TARGET" -o TARGET,SOURCE,FSTYPE,OPTIONS
echo "Checking underlying data..."
mkdir -p /tmp/root_bind
mount --bind / /tmp/root_bind
du -sh /tmp/root_bind${TARGET} 2>/dev/null
umount /tmp/root_bind
echo -e "\n--- 3. Deleted but held files (lsof) ---"
lsof -nP | grep deleted | awk '{printf "PID:%-8s FD:%-6s SIZE:%-12s CMD:%-15s FILE:%s\n", $2, $4, $7, $1, $9}'
echo -e "\n=== Summary ==="
df -h "$TARGET"
echo "Run with target path: $0 /var"
chmod +x /usr/local/bin/find_lost_space.sh
find_lost_space.sh /var
logrotate(copytruncate 或 sharedscripts + postrotate reload),避免手動 rm 導致持有df vs du 差值,差值 > 10% 觸發告警df 看宿主機,du 看容器層,差異更大,需宿主機排查lsof + grep deleted 必查項磁盤空間「失蹤」不是鬼故事,而是 df/du 統計視角差異的必然結果。掌握 lsof + grep deleted、mount --bind 探底、隱藏文件統計三大核心技能,即可在 5 分鐘內定位 99% 的空間失蹤案件。