欢迎光临
我们一直在努力

Linux 删除文件后磁盘空间不释放怎么办?df、du 与 lsof 排查教程

服务器提示磁盘空间不足,删除几个大日志以后,再执行 df -h,发现可用空间几乎没有变化。这是 Linux 运维中比较常见的一类问题。

文件从目录里消失,并不一定代表它占用的空间已经释放。某些进程可能仍然打开着这个文件,也可能是检查了错误的分区,或混淆了 df 与 du 的统计范围。

本文介绍一套从文件系统、打开文件到服务处理的排查方法,适用于莱卡云 Linux 云服务器及常见 Linux 环境。命令以 Ubuntu、Debian 等使用 GNU 工具的系统为例,涉及进程与服务的检查建议使用 root 或具备相应 sudo 权限的账号。

一、为什么文件删除了,空间还被占用?

在 Linux 中,文件名、文件内容和进程打开的文件描述符,是不同的概念。

删除文件时,通常先移除目录中的文件名。如果这是文件的最后一个硬链接,但仍有进程打开着它,文件内容就会继续存在,进程甚至还可以继续写入。

这时可能同时出现三个现象:

  • ls 已经找不到原文件。
  • du 扫描目录时不再统计这个文件。
  • df 仍然显示相关空间被占用。

对常见本地文件系统而言,等最后一个相关打开引用被释放,且没有其他保留数据的机制时,空间才可以回收。快照、共享数据块等情况还需要单独判断。

因此,发现这种现象以后,先查占用来源,不要继续盲目删除其他业务文件。

二、先确认文件原来位于哪个文件系统

使用df和findmnt确认日志所在文件系统

假设刚才删除的是 /var/log 下的日志,先检查这个目录所在的文件系统:

df -hT /var/log
findmnt -T /var/log -o TARGET,SOURCE,FSTYPE

重点看 df 的文件系统、类型和挂载点,以及 findmnt 的 TARGET、SOURCE。

如果 /var/log 属于根文件系统 /,应观察根文件系统的可用空间;如果日志在独立的数据盘上,则应观察那个数据盘。

例如,删除 /data 中的文件,并不会让另一个文件系统上的 / 增加可用空间。

原文件已经不存在时,命令应指向它仍然存在的父目录。不要继续把已经删除的完整文件路径传给 df。

三、df 和 du 为什么对不上?

两个命令的统计对象不同:

命令主要查看什么
df文件系统层面的容量、已用空间和可用空间
du沿目录树统计能够访问到的文件占用

如果要分析根文件系统,可以执行:

df -hT /
du -xhd1 /

du 的 -x 表示不跨入其他文件系统,-d1 表示只显示一层目录汇总。

如果出问题的是独立挂载的 /data,应把两条命令中的 / 都换成 /data。

文件较多时,du 可能运行较久,建议在业务低峰执行。若出现权限错误,统计结果可能不完整,不能忽略错误后直接比较数字。

另外,df -h /var/log 查看的是 /var/log 所在的整个文件系统,而 du -sh /var/log 只统计这个目录。两者本来就不应该要求相等。

即使统计范围一致,文件系统元数据、快照、共享数据块和正在变化的文件,也可能造成差异。df 与 du 不一致,只是排查线索,不能单凭这一点断定是文件被进程占用。

四、用 lsof 查找已删除但仍被打开的文件

执行:

lsof -nP +L1

其中:

  • +L1:筛选硬链接数小于 1 的打开文件。
  • -n:不进行主机名解析。
  • -P:不把端口号转换成服务名称。

如果提示没有 lsof,Ubuntu、Debian 可以在软件源正常且仍有安装空间时执行:

apt update
apt install -y lsof

下面是说明字段用的示例,不代表你的实际输出:

COMMAND  PID USER FD TYPE DEVICE   SIZE/OFF NLINK   NODE NAME
nginx   2468 root 5w  REG  252,1 4294967296     0 123456 /var/log/nginx/access.log (deleted)

重点关注以下字段:

字段判断方法
COMMAND、PID哪个进程正在使用文件
FD文件描述符编号,例如 5w 中的编号是 5
TYPE是否为普通文件,例如 REG
DEVICE、NODE辅助确认文件所在设备和 inode
SIZE/OFF普通文件这里通常显示逻辑大小,也可能因对象类型显示偏移量
NLINK0 表示已经没有普通目录硬链接
NAME原路径及可能出现的 (deleted) 标记

示例里的 4294967296 约为 4 GiB,但逻辑大小不一定等于实际占用空间,稀疏文件尤其如此。

同一个文件可能被多个进程或多个描述符同时打开。不能直接把每一行的大小相加,应结合 DEVICE 和 NODE 识别重复记录。

也不要把所有 (deleted) 都当作系统盘泄漏。memfd、共享内存和 tmpfs 对象需要与实际告警的文件系统区分。

使用lsof查找已删除但仍被进程占用的文件

五、确认 PID 对应的程序和服务

找到可疑 PID 后,先确认进程身份。下面的 2468 需要替换成实际 PID:

ps -p 2468 -o pid,ppid,user,comm
lsof -nP -a -p 2468 +L1

第二条命令用 -a 将 PID 条件与已删除文件条件组合起来,只查看这个进程相关的记录。

在使用 systemd 的服务器上,还可以尝试查看该 PID 所属的服务:

systemctl status 2468 --no-pager

如果需要进一步检查示例中编号为 5 的描述符,可以执行只读查询:

readlink /proc/2468/fd/5
stat -Lc 'size=%s blocks=%b block_unit=%B links=%h' /proc/2468/fd/5

这里的 blocks × block_unit 可辅助判断文件实际分配的数据块大小,但不能据此保证释放相同数量的物理空间,例如快照或共享块仍可能保留数据。

PID 和描述符都可能变化。如果查询时提示不存在,先重新运行 lsof,不要继续对旧 PID 执行操作。

六、如果是 Nginx 日志,优先重新打开日志

如果确认被删除的是 Nginx 访问日志或错误日志,可以使用 Nginx 自身的日志重开功能。

先确认使用的是当前实例对应的 Nginx 程序和配置,然后检查:

nginx -t

检查通过后执行:

nginx -s reopen

reopen 会通知 Nginx 重新打开日志文件。操作成功后,相关进程会关闭旧日志的打开引用,并使用当前配置指定的日志路径。

如果服务器由宝塔等面板管理,或者安装了多个 Nginx,应使用实际实例的程序路径、配置及必要的 -c、-p 参数,不能默认命令行中的 nginx 就是正在提供服务的那一套。

完成后再次检查 lsof、磁盘空间和网站访问,不能只看命令没有报错。

如果网站同时出现 502,可以继续参考本站:Nginx 出现 502 Bad Gateway 怎么办?常见原因与排查教程。

检查Nginx配置并重新打开日志文件

七、其他程序应该怎么释放占用?

不同程序处理日志的方式不一样。优先查找程序是否支持日志重开、日志轮转或官方维护命令。

如果程序没有相关功能,并且已经确认占用来自该服务,可以安排维护时段,正常重启对应服务。

下面的服务名只是占位示例,必须替换成已经确认的实际单元名:

systemctl restart your-app.service
systemctl status your-app.service --no-pager

服务重启可能中断连接或正在执行的任务,应根据业务安排。数据库、队列等服务尤其需要确认业务依赖和数据状态。

不要把强制杀进程、直接清空 /proc/PID/fd/FD 或重启整台服务器当成通用清理步骤。误处理数据库文件或业务数据文件,可能造成数据损坏。

如果同一个文件还有其他进程持有,仅重启其中一个进程,也可能无法释放空间。

八、处理完成后,怎样确认空间真的释放?

重新执行:

lsof -nP +L1
df -hT /var/log

将 /var/log 替换成原文件所在的实际目录。

至少确认三件事:

  1. 原先占用空间的文件记录是否已经消失。
  2. 对应文件系统的可用空间是否增加。
  3. 服务是否正常,新的日志是否继续写入。

df -h 会进行单位换算和显示舍入。如果需要更细地比较前后变化,可以在处理前后分别执行:

df -B1 /var/log

不要只比较百分比。大容量文件系统释放几百 MB 后,使用率百分比可能没有明显变化;同时有其他程序持续写入时,也可能抵消刚释放的空间。

检查文件引用和磁盘可用空间确认释放结果

九、lsof 没查到明显占用,还能检查什么?

没有查到记录,不代表一定没有问题。应先确认命令是在正确主机、正确权限和需要检查的进程环境中运行。

接下来按以下方向检查:

1. 文件只是进入了回收站

通过桌面文件管理器或部分管理面板删除文件,可能只是移动到回收站,并没有真正移除文件。

应查看对应软件的回收站规则,并先确认文件不再需要。

2. 文件还有其他硬链接

删除一个文件名,并不代表所有指向同一文件的硬链接都已经消失。

这种情况不属于 +L1 筛选的零链接文件,需要结合已知的其他路径和 inode 判断。

3. 快照仍然引用旧数据

Btrfs、ZFS 等文件系统的快照可能继续保留被删除文件的数据。应按实际文件系统的快照和空间管理方式排查。

4. inode 已经耗尽

如果磁盘还有容量,但新文件仍然无法创建,可以检查:

df -i /var/log

大量小文件可能耗尽 inode。此时需要确认文件来源和保留规则,单纯删除几个大文件不一定能够解决问题。

5. 数据被挂载点覆盖

某个目录原来存有文件,后来又挂载了另一个文件系统,原文件可能被新的挂载遮住。普通目录遍历看不到它们,但底层文件系统仍然计算占用。

遇到这种情况,应先核对挂载关系,再安排维护检查,不要在生产环境直接卸载正在使用的数据盘。

NFS 等网络文件系统还有不同的删除和引用处理方式,不应直接套用本地磁盘的判断结果。

十、Docker 日志占用需要单独区分

如果服务器运行 Docker,先分清两类文件:

  • 应用写入挂载目录的普通日志。
  • Docker 日志驱动管理的容器标准输出、标准错误日志。

对于前者,应让实际写入日志的应用重新打开文件,或按业务需要正常重启对应服务。

对于 Docker 日志驱动管理的文件,不建议绕过 Docker 直接删除或清空。这样既可能破坏日志管理,也可能出现文件已经删除、相关进程却仍持有引用的情况。

日志大小限制和轮转配置,可以参考本站:Docker 容器日志占满磁盘怎么办?日志清理与大小限制教程。

如果清理或重建容器后,应用出现数据不见、重新初始化等现象,应停止继续清理,并参考:Docker 容器重建后数据不见了怎么办?

磁盘占用排查不需要顺手删除业务数据卷。

十一、怎样减少这种问题再次发生?

长期解决办法是设置合适的日志轮转和保留策略,而不是等磁盘满了再手工删除。

建议结合实际业务做好以下设置:

  • 配置日志按时间或大小轮转。
  • 轮转后,让应用按官方方式重新打开日志。
  • 为 Docker 日志设置合适的大小和文件数量限制。
  • 同时监控磁盘容量、inode 和日志增长速度。
  • 在维护记录中保留占用进程、文件路径和处理方法。

如果日志持续异常增长,还需要检查请求量、错误日志、循环报错和程序配置。只缩短保留时间,不能代替查明增长原因。

十二、总结

Linux 删除文件后磁盘空间没有释放,常见原因之一是进程仍然打开着已删除文件,但也可能涉及统计范围、回收站、硬链接、快照或挂载关系。

排查时先用 df 和 findmnt 确认目标文件系统,再用 du 了解目录占用,通过 lsof -nP +L1 查找已删除但仍被打开的文件。

确认程序和业务归属后,优先使用日志重开或正常维护方式释放引用,最后同时检查磁盘空间与服务状态。

把日志轮转、容量告警和日常检查做好,才能减少“文件删了,磁盘还是满”的反复出现。

赞(0)
未经允许不得转载:莱卡云 » Linux 删除文件后磁盘空间不释放怎么办?df、du 与 lsof 排查教程