CentOS 7 删除文件却不释放空间?从 inode、文件描述符到 VFS 的底层原理解析

这是在帮一个用户看服务器遇到的问题,他用的是Hostease的独立服务器,因为服务器用的时间也比较长了,磁盘比较满,所以做了一次清理,但是在删除文件之后,发现他删除掉几百个G的数据之后,磁盘空间并没有空出来。

我拿到之后先df -h看了下:

光看df结果,文件确实已经满的再满了,此时用户已经删除大量文件,空间却没有释放;并且紧接着重启了服务,而重启前后前后,df 变化也不明显。

这类问题,99% 本质都与 inode 引用计数有关。

理解 Linux 删除文件的真实过程

很多人误以为:

rm = 删除文件内容

实际上:

rm 只是删除"目录项"(directory entry)

我们必须理解 Linux 文件系统的三个核心概念:

1️.inode

inode 保存的是以下信息:

文件大小

权限

数据块指针

链接数(link count)

时间戳

文件名不存储在 inode 里。

2️.目录项(dentry)

目录本质是:

文件名 → inode 号

删除文件时,删除的是目录项,而inode和数据块仍然存在。

3️.文件描述符(File Descriptor)

当进程打开文件:

fd = open("test.log", O_WRONLY);

内核会在进程表中创建 file descriptor,引用对应 inode,增加引用计数。

什么时候磁盘空间才会真正释放?

磁盘空间释放的条件:

1.link count == 0

2.没有进程持有该 inode

只有两个条件同时满足,内核才会释放 inode和数据块,回收空间。

为什么 lsof | grep deleted 会出现大量文件?

执行:

lsof | grep deleted

示例:

php-fpm 4510 root 3u REG ... /tmp/ZCUDnRoeZv (deleted)

简单来说就是,目录项已删除,link count 已为 0,但进程仍持有 file descriptor,inode 仍被引用,数据块无法释放。

这是一种非常经典的"幽灵文件"。

从内核角度看"deleted 文件"

在 /proc 下可以看到:

ls -l /proc/4510/fd/

会看到类似:

3 -> /tmp/ZCUDnRoeZv (deleted)

实际上文件名已不存在,但 fd 仍然指向 inode,进程依然可以写入,这也是为什么日志文件可以"删掉还继续增长"。

df 与 du 为什么会不一致?

df 统计的是文件系统已分配的数据块数量,它直接读取超级块(superblock)信息。

而du 是遍历目录树,统计可见文件的 inode 占用。

deleted 文件会导致什么?

df 统计的是实际已用 block

du 统计的是当前目录可见文件

因此:

df 显示 100%

du 却找不到大文件

这几乎可以确定:

存在被进程占用的 deleted 文件

真实排查流程(技术向)

1.查看磁盘使用

df -h

2.查看目录占用

du -xhd1 / 2>/dev/null | sort -hr

如果 du 总和远小于 df,说明存在"不可见占用"。

3️.检查 deleted inode

lsof | grep deleted

或:

lsof -nP | grep '(deleted)'

4️.查看具体进程 fd

ls -l /proc/PID/fd

5. 释放方式

推荐方式

优雅重启服务:

systemctl restart 服务名

非优雅方式(极端场景)

直接 kill 进程:

kill -9 PID

不建议生产环境滥用。

隐藏回收站目录的本质

例如:

/.Recycle_bin

这不是内核机制,而是:

面板逻辑层实现

文件被移动而非删除

底层发生的是:

rename(old_path, /.Recycle_bin/xxx)

inode 不变,仅目录项变化。

因此:

du 会看到

df 会统计

但用户误以为已删除

在这个客户的案例里,虽然存在一些幽灵文件,但实际上大头是在/.Recycle_bin 中:

ext4 延迟分配与日志机制补充

在 ext4 下:

采用延迟分配(delayed allocation)

使用 journal 日志机制

如果磁盘 100%:

journal 无法提交

某些写入可能阻塞

服务异常

因此:

根分区长期 100% 是非常危险的状态。

进阶:如何快速统计 deleted 占用总量?

可以使用:

lsof | grep deleted | awk '{print 7}' \| awk '{sum+=1} END {print sum/1024/1024 " MB"}'

用于估算被占用空间。

总结

删除文件 ≠ 释放空间,真正释放空间的条件是:

inode link count = 0

且无 file descriptor 引用

df 与 du 不一致的根本原因是df 统计 block,du 统计目录可见 inode,当你理解了 inode 与 file descriptor 的关系,这类问题将不再神秘。

相关推荐
大鹏说大话17 小时前
从爬虫到决策引擎:大数据下自媒体如何用Python挖掘用户痛点
开发语言·爬虫·python
Niuguangshuo17 小时前
silero-vad:超轻量级开源 VAD 实践指南
开发语言·python
2501_9446761618 小时前
揭秘!WORDTIP公司靠不靠谱?小白必看
大数据·人工智能·python
Minner-Scrapy19 小时前
Scrapy 2.17 源码解析:Scheduler 调度器与磁盘/内存双队列
java·爬虫·python·scrapy·网络爬虫·twisted
CODER030419 小时前
Anaconda和Mamba创建环境管理包常用命令合集
python·深度学习·conda·虚拟环境·mamba·常用命令大全
闲猫19 小时前
LangGraph / Capabilities / Fault tolerance
python·agent·langgraph
IvanCodes19 小时前
Python 基础语法(一):变量、数据类型与运算符
python
智购科技自动售卖机厂家20 小时前
2026自动售货机OTA升级系统设计:从全量升级到差分升级的带宽优化工程实践~YH
大数据·人工智能·numpy·pyqt·fastapi
程序员三藏20 小时前
浅谈性能测试
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·性能测试
l12586520 小时前
# RAG向量数据库优化实战:HNSW索引调参与生产级性能设计
数据库·python·mysql·langchain