上一篇 下一篇 分享链接 返回 返回顶部

删除文件但磁盘空间未恢复,Linux如何通过/proc和df核对真实占用?

发布人:Minchunlin 发布时间:2026-10-08 19:26 阅读量:2

删除文件后,df 显示磁盘使用量没有下降,常见原因是文件名已经从目录中移除,但进程仍持有该文件的打开句柄。此时,文件内容对普通目录遍历不可见,文件系统却仍需保留对应数据块,直到最后一个打开句柄关闭。

在 Linux 上,可以先用 df 确认具体文件系统的空间变化,再用 lsof +L1 或 /proc/<PID>/fd 查找已删除但仍打开的文件。找到目标后,通常应通过应用支持的日志重开方式,或在评估影响后重启对应进程来释放空间。不要仅凭文件名就直接操作 /proc 下的文件描述符:它指向的是进程正在使用的文件,错误写入可能导致数据丢失或服务异常。

A5数据提供中国香港、美国、日本、韩国、中国台湾、新加坡和马来西亚等地区的物理服务器,覆盖SSD、NVMe及大容量机械硬盘存储配置,可承载网站后台、数据库、接口服务与持续日志写入等Linux业务场景。结合不同CPU、内存、带宽和线路资源,A5数据为文件存储、应用运行及多地区业务部署提供服务器基础。

适用环境与准备条件

以下步骤适用于常见 Linux 发行版上的本机文件系统排查,例如使用 ext4 或 XFS 的服务器。命令以 GNU/Linux 环境为主;不同发行版的工具版本和权限策略可能略有差异。

开始前确认:

  • 有权限读取系统进程信息。查看其他用户进程时,通常需要 root 或 sudo 权限。
  • 已记录磁盘告警对应的挂载点、业务进程和最近的删除操作;如果是生产服务,应确认维护窗口或变更流程。
  • 先用只读命令定位问题,不要在定位前重启服务、清空日志或改写文件描述符。
  • 如果服务器运行在容器中,确认检查的是宿主机还是容器内部。容器内看到的 /proc、挂载点和宿主机可能不同。

本文中的终端输出均为便于判断的示例,不代表特定服务器的实际执行结果。

第一步:确认空间没有看错文件系统

df 按文件系统统计已用空间,du 则遍历目录中仍可见的文件。应先确认告警对应的挂载点,再比较两者,避免把不同挂载点的结果混在一起。

查看所有挂载点的空间:

df -hT

再针对具体目录检查其所在文件系统。下面以 /var/log 为例:

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

检查该文件系统中可见目录占用:

sudo du -xsh /var/log

-x 表示不跨文件系统,避免进入挂载在该目录下的其他文件系统。若要查看一级子目录占用,可使用:

sudo du -xhd1 /var/log

示例结果:

Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/vda1      ext4   80G   76G  1.2G  99% /

72G     /var/log

如果 df 显示文件系统已用约 76G,而目录遍历只统计到约 72G,差额可能来自已删除但仍打开的文件,也可能来自其他目录、文件系统元数据、保留空间、快照或不同挂载层。这个差值本身不能证明一定存在已删除文件,需继续核查。

同时查看 inode 使用情况:

df -ih -- /var/log

如果 inode 已满,即使还有可用字节,也可能无法创建新文件。此时应区分“容量不足”和“inode 不足”,两者的排查重点不同。

本步判断标准:

  • findmnt -T 确认目标路径实际属于哪个挂载点。
  • df 与 du 必须对照同一个文件系统;不要拿整个根分区的 df 与某个子目录的 du 直接作精确差额比较。
  • df 与 du 有明显差距时,继续检查打开句柄;差距不明显也不能完全排除单个大文件或多个小文件被删除但仍占用的情况。

第二步:用 lsof 查找已删除但仍打开的文件

如果系统已安装 lsof,优先使用它筛选链接数小于 1 的打开文件:

sudo lsof -nP +L1

常见输出示例:

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NLINK   NODE NAME
app      1842 svc    12w   REG  253,0  8.0G       0 123456 /var/log/app.log (deleted)

重点看以下字段:

  • COMMAND、PID:持有文件的进程及进程号。
  • FD:文件描述符编号和访问模式。示例中的 12w 表示描述符 12 以可写方式打开。
  • SIZE/OFF:文件大小或偏移信息。它不一定等于实际占用的数据块。
  • NLINK:链接数。通常为 0 且名称带 (deleted),说明目录链接已不存在。
  • NAME:原路径及删除标记。

若输出中存在目标文件,并且其大小与 df、du 的差额大致相符,就有较强证据表明该进程持有已删除文件。不过,SIZE/OFF 是文件逻辑大小的线索,不代表文件在磁盘上一定占用同样多的块:稀疏文件、压缩或文件系统实现都会影响实际占用。

只查看指定文件系统上的候选项,可以先从输出中筛选路径;但要注意,文件被删除后,原路径已不存在,lsof 显示的是进程打开句柄所关联的名称。筛选结果应再结合进程和文件描述符核实,不能只按字符串匹配就执行处置。

如果提示 lsof: command not found,不要为了临时排查而直接运行来历不明的脚本。可按发行版的软件管理流程安装发行版提供的 lsof 包,或使用下一步的 /proc 只读检查。

第三步:通过 /proc 核对进程和文件描述符

Linux 的 /proc 是内核提供的进程信息接口。/proc/<PID>/fd/ 中的条目对应进程当前打开的文件描述符;已删除的文件常显示为原路径后附加 (deleted)。

第三步:通过 /proc 核对进程和文件描述符配图

假设 lsof 显示进程号为 1842、描述符为 12,先核实进程身份和句柄目标:

ps -p 1842 -o pid,ppid,user,comm,args
sudo readlink "/proc/1842/fd/12"

可能看到:

  PID  PPID USER  COMMAND  COMMAND
 1842     1 svc   app      /usr/local/bin/app --config /etc/app.conf

/var/log/app.log (deleted)

这表示进程 1842 的描述符 12 仍指向一个已删除文件。再次查看描述符元数据:

sudo cat /proc/1842/fdinfo/12

示例:

pos:    8589934592
flags:  0102001
mnt_id: 25
ino:    123456

ino 是 inode 号,mnt_id 标识挂载信息,pos 是当前文件偏移;它们可用于辅助核对,但单独一个 inode 号或文件偏移不能证明该文件占用了多少磁盘块。

还可以读取文件大小和已分配块信息:

sudo stat -Lc 'size=%s bytes, blocks=%b, block_unit=%B' "/proc/1842/fd/12"

示例:

size=8589934592 bytes, blocks=16777216, block_unit=512

这里 size 是逻辑字节数;blocks 的单位由 block_unit 给出。示例中已分配块约为 16777216 × 512 字节,即约 8 GiB。实际结果会受文件系统、稀疏文件和写入状态影响。该命令只读取元数据,不会修改文件。

检查时,如果 /proc/1842/fd/12 已不存在,可能是进程关闭了句柄、进程退出,或 PID/FD 已发生变化。此时重新运行 lsof -nP +L1,不要继续对旧编号操作。

本步判断标准:

  • ps 显示的进程身份与业务服务相符。
  • readlink 显示目标带有 (deleted),且 lsof 的 PID、FD、inode 等信息能够对应。
  • stat 显示该句柄仍有一定数据块占用。逻辑大小很大但块数较小,可能是稀疏文件,释放空间效果不能只按逻辑大小估算。
  • 如果该句柄属于关键数据库、队列或业务进程,不要因为文件名看起来像日志就直接关闭进程。

第四步:选择释放空间的安全方式

发现目标后,先确认它是什么文件、由哪个程序管理,以及程序是否仍在向该文件写入。释放句柄会改变进程和文件的运行状态,操作前应评估服务影响,并按生产变更流程准备备份、告警观察和回退方案。

优先使用应用支持的日志重开方式

日志文件被删除但进程仍持有旧句柄时,应用可能继续向旧文件写入;这部分数据不会通过原路径访问。若程序支持重新打开日志文件,可按其文档或服务运维规范执行日志重开,再检查进程是否已切换到新文件。

不同程序的信号、管理接口和配置并不相同,不能把某个服务的信号命令套用到其他程序。执行前需确认:

  • 该应用确实支持重新打开日志。
  • 配置中的新日志路径可写,所属目录和权限正确。
  • 重开操作不会触发不必要的配置变更或业务重载。
  • 操作后通过 lsof 检查旧 FD 是否关闭,新日志文件是否正常生成。

如果应用不支持日志重开,或无法确认行为,不要试探性发送信号。

评估后重启对应服务

如果应用无法安全重开文件,且确认重启可以接受,可在维护窗口中重启确切持有该 FD 的服务。重启会关闭进程打开的文件描述符,内核在最后一个句柄关闭后才可释放该文件占用;同时也可能造成连接中断、任务暂停或短暂不可用。

先核对 PID 所属服务和当前状态:

ps -p 1842 -o pid,ppid,user,comm,args
systemctl status 1842

systemctl status <PID> 在使用 systemd 的系统上可用于查看该 PID 所属单元;若系统不支持这种查询方式,应根据进程命令行、父进程和服务管理配置确认服务名,不要猜测单元名称。

确认服务和影响范围后,按该环境的变更流程执行重启。例如,只有在已经确认实际服务单元名为 app.service 时,才使用:

sudo systemctl restart app.service

重启前确保应用有可用配置和必要的数据备份;如果进程承载有状态任务,先确认任务能否恢复。不要为了释放空间而批量重启未知进程。

不要把直接改写 /proc FD 当成通用清理方式

有些操作方法会尝试截断 /proc/<PID>/fd/<FD> 指向的文件。这可能立刻改变进程仍在使用的数据,造成日志内容丢失、应用状态异常,甚至破坏数据库或队列文件。尤其当目标类型、程序行为或写入状态不明确时,禁止直接执行 truncate、重定向清空或类似写操作。

只有在应用厂商或维护文档明确要求、数据可恢复、操作范围经过审批且已准备备份时,才考虑针对具体应用的专用处置方式;这不属于通用排障命令。

第五步:复查空间是否释放

应用重开日志或服务重启后,重新运行:

sudo lsof -nP +L1
df -hT -- /var/log
sudo du -xsh /var/log
df -ih -- /var/log

如果目标行已从 lsof +L1 消失,且对应文件系统的 df 可用空间增加,说明相关已删除文件的句柄已关闭并释放了空间。du 的结果可能变化较小,因为被删除文件本来就不在目录遍历统计中。

示例:

# 操作前:目标文件仍在 lsof 输出中
app  1842 svc  12w REG 253,0 8.0G 0 123456 /var/log/app.log (deleted)

# 操作后:该条目消失
# df 显示文件系统可用空间增加

空间变化不一定精确等于 SIZE/OFF:文件可能是稀疏文件,其他进程也可能同时写入或清理数据,文件系统还可能存在保留空间和元数据开销。判断时应综合看 lsof 条目是否消失、df 的可用空间变化,以及应用日志是否已写入新路径。

如果 lsof 中没有目标条目,或空间仍未恢复,可继续检查:

  • 确认挂载点一致。 重新执行 findmnt -T 和 df -hT,排除检查了不同文件系统的情况。
  • 查找其他已删除句柄。 lsof +L1 可能列出多个进程或多个文件,不要只处理第一条。
  • 检查硬链接。 文件有多个硬链接时,删除一个路径不会让链接数变为 0,文件仍可通过其他路径访问;这类文件不一定出现在 +L1 结果中。
  • 检查目录中其他占用。 用 du -xhd1 逐级缩小范围,确认是否存在仍可见的大文件。
  • 检查挂载层和容器。 容器的写时复制层、宿主机挂载目录和容器内部目录可能显示不同的空间视图,应在持有实际文件系统的主机或命名空间中核对。
  • 区分容量与 inode。 df -h 看字节空间,df -i 看 inode;inode 耗尽时,删除已打开的大文件未必能解决创建小文件失败的问题。
  • 考虑文件系统特性。 快照、预留块、压缩、延迟分配和文件系统元数据会影响统计结果。若差异仍无法解释,应由熟悉该文件系统的人员进一步检查,而不是直接运行修复或强制卸载命令。

异常情况与处理边界

没有权限查看其他进程

普通用户运行 lsof 或访问 /proc/<PID>/fd 时,可能因权限策略、容器隔离或系统安全配置而看不到目标。使用经过授权的 sudo 重试,并确认命令是在正确的宿主机或容器环境中执行。不要通过放宽 /proc 权限来解决临时排查问题。

lsof 没有结果,但 df 与 du 仍不一致

这并不代表空间一定被已删除文件占用。先核对文件系统和挂载命名空间,再检查目录、硬链接、快照及文件系统元数据等因素。如果系统安装了多个版本或运行环境不同,确保 lsof 检查的是实际发生空间告警的主机,而不是容器内的视图。

重启后空间没有明显增加

可能的原因包括:释放的是稀疏文件,实际分配块较少;同一文件还有其他进程持有句柄;该文件并非差额的主要来源;或查看了错误的挂载点。再次执行 lsof -nP +L1,确认是否还有对应 FD,再对照 stat 和 df。不要仅根据重启前后的 du 变化判断成功。

日志重开后又迅速占满

这说明空间释放后,应用可能仍在持续生成大量日志。确认新日志路径、轮转策略、日志级别和增长速率;先定位产生日志的程序及原因,再按服务配置调整。不要通过反复删除当前日志文件代替容量治理,否则旧文件句柄可能再次造成 df 与 du 不一致。

验收与回滚检查项

完成处理后,逐项确认:

  • findmnt -T 和 df -hT 指向预期的文件系统,字节空间与 inode 使用率均已复核。
  • lsof -nP +L1 中目标文件条目已消失;若仍存在,已确认剩余 PID 和 FD 的归属。
  • 目标服务状态正常,日志或业务数据写入的是预期路径,应用没有持续报错。
  • 对空间变化的判断基于 df、文件描述符状态和实际分配块,而不是只看文件名或逻辑大小。
  • 如重启造成服务异常,按应用自身的恢复流程处理;使用重启前保存的配置和备份恢复,必要时回退与本次变更关联的日志路径或服务配置。
  • 不要尝试“恢复”已删除文件描述符指向的数据,除非已有经验证的数据恢复方案。文件句柄关闭后,内核释放的块通常不能再通过该句柄访问。

处理这类问题的安全顺序是:先确认挂载点和统计口径,再通过 lsof 与 /proc 交叉核对,最后使用应用支持的方式关闭旧句柄,并重新检查 df、du 和服务状态。