最准方法是用 find 配合 stat 递归统计子目录 inode 数:for d in /*; do [ -d "$d" ] && echo "$(find "$d" -xdev -printf '.' | wc -c) $d"; done 2>/dev/null | sort -nr | head -10。

查哪个目录占用了最多 Inode
直接用 find 配合 stat 统计子目录的 inode 数量最准,尤其当某个深层子目录(比如日志归档、临时上传目录)悄悄生成海量小文件时,df -i 只能告诉你根分区快满了,但找不到具体位置。
执行以下命令可按 inode 数量倒序列出当前路径下所有一级子目录的占用情况:
for d in /*; do [ -d "$d" ] && echo "$(find "$d" -xdev -printf '.' | wc -c) $d"; done 2>/dev/null | sort -nr | head -10
说明:-xdev 确保不跨文件系统统计;printf '.' 是轻量替代 ls -a | wc -l 的方式,避免因文件名含换行符或特殊字符出错;2>/dev/null 屏蔽权限拒绝报错。
- 若要查指定路径(如
/var),把/*换成/var/* - 结果中数字越大,表示该目录下(含所有子目录)的 inode 占用越多
- 注意:这个统计是递归的,耗时取决于目录深度和文件总数,生产环境慎在
/下直接跑
定位高 inode 密度的子目录(按每层展开)
知道大头在 /var 后,不能直接冲进 /var/log 或 /var/spool 盲扫——得一层层确认哪级目录开始“异常密集”。核心思路是对比「目录项数量」与「实际文件数」,快速识别出“空目录多”或“文件极碎”的路径。
例如检查 /var/log 下各子目录的 inode 使用密度:
find /var/log -maxdepth 1 -type d | while read d; do printf "%s: %s\n" "$d" "$(find "$d" -maxdepth 1 -type f | wc -l)"; done | sort -t: -k2nr
关键点:-maxdepth 1 限制只统计当前目录下的文件(不含子目录),这样能看出哪些目录光是“壳”就建了一堆(比如大量空日志轮转目录),哪些真塞了上万小文件(如 journal 的二进制日志碎片)。
-
/var/log/journal常见于 systemd 系统,单个.journal~文件不算什么,但拆成几百个.journal+.journal~就会吃掉大量 inode -
/var/spool/postfix/maildrop或/var/spool/clientmqueue在邮件队列堆积时,每个待发邮件一个文件,极易爆 inode - 容器环境要额外看
/var/lib/docker/overlay2下的diff目录,镜像层叠加可能产生冗余 inode
为什么 df -i 显示已用 100%,但 find ... | wc -l 加起来远小于此
这是最常让人困惑的点:明明算出来总共才几十万文件,df -i 却说 inode 已用完。根本原因是「已删除但未释放」的文件仍占着 inode——即进程还打开着这些文件的 fd,文件系统无法回收其 inode。
验证方法:
lsof +L1
这条命令列出所有 link count 为 0(即已被 unlink 删除)但仍被进程持有的文件。输出里常见的有:
-
nginxworker 进程长期持有已删的日志文件(典型场景:logrotate 后没发HUP) -
java应用未关闭临时文件流,尤其使用File.createTempFile()但没调deleteOnExit() -
rsync或cp中断后残留的 .~tmp 文件,虽被 unlink 但父进程未退出
解决办法不是杀进程,而是先确认是否可重启对应服务;若不可中断,可用 echo > /proc/[pid]/fd/[fd_num] 清空句柄内容(谨慎!仅适用于可覆盖写场景),或等进程自然结束。
清理后 inode 不释放?检查 ext4 的 reserved blocks 和 lazyinit
执行 rm -rf 大量小文件后,df -i 仍不下降,可能是 ext4 文件系统在后台异步初始化 inode table,尤其在新建的大容量分区上启用 lazy_itable_init 特性时。
查看是否启用:
tune2fs -l /dev/sda1 | grep "Filesystem features"
若输出含 lazy_itable_init,说明 inode table 初始化被延迟到首次使用时才进行,此时 df -i 显示的是“理论最大 inode 数”,而非“已分配可用 inode 数”。真正可用 inode 数需等初始化完成。
- 强制触发初始化:
e2fsck -f -y /dev/sda1(需卸载或强制只读检查) - 日常预防:创建新 ext4 分区时加
-E lazy_itable_init=0关闭该特性 - 注意:
reserved blocks(默认 5%)也会计入df -i的 total,但它不用于普通用户文件,只留给 root 紧急使用,这部分不可被清理释放
inode 问题从来不是“删完就完”,它连着进程生命周期、文件系统特性和应用行为设计。一次看似简单的 rm -rf,可能只是把压力从磁盘空间转移到了内核缓存或进程句柄上。

















