为什么打开已删除文件的文件句柄似乎会填满硬盘驱动器

为什么打开已删除文件的文件句柄似乎会填满硬盘驱动器

因此,长话短说,我编写了一个(python)程序,它打开了很多文件,在其中写入数据,然后删除了这些文件,但没有正确关闭文件句柄。一段时间后,该程序由于磁盘空间不足而停止。

bash 中的自动完成失败cannot create temp file for here-document: No space left on device"lsof -nP +L1显示大量不再存在的文件。

杀死我的程序后,所有文件句柄都被关闭,磁盘空间再次“空闲”,一切都很好。

为什么会发生这种情况?磁盘空间并未物理填满。或者文件句柄的数量是否有限?

答案1

在 Unix 中删除文件只是删除对其数据的命名引用(因此系统调用名称为unlink/ unlinkat,而不是delete)。为了释放数据本身,不得有其他对其的引用。可以通过以下几种方式获取参考:

  1. 文件系统上不得再引用此数据(st_nlink必须为 0)——硬链接时可能会发生这种情况。否则,当我们仍然可以从文件系统访问数据时,我们就会删除数据。
  2. 打开的文件句柄中不能进一步引用此数据(在 Linux 上,内核中的相关 必须为 0)struct filef_count否则,数据仍然可以通过读取或写入文件句柄(或/proc/pid/fd在 Linux 上)来访问或更改,并且我们需要在某个地方继续存储它。

一旦满足这两个条件,数据就有资格被释放。由于您的情况违反了条件#2——您仍然有打开的文件句柄——数据继续存储在磁盘上(因为它没有其他地方可去),直到文件句柄被关闭。

有些程序甚至使用它来简化数据清理。例如,想象一个程序需要在磁盘上存储一些大数据以进行中间工作,但不需要与其他人共享。如果它打开然后立即删除该文件,它可以使用它,而不必担心确保它们在退出时清理——打开的文件描述符引用计数在close(fd)或退出时自然会降至 0,并且相关空间将被释放程序是否正常退出。

检测

仍由文件描述符保持打开状态的已删除文件可以通过 找到lsof,使用如下所示:

% lsof -nP +L1
COMMAND     PID  USER   FD   TYPE DEVICE SIZE/OFF NLINK      NODE NAME
pulseaudi  1799 cdown    6u   REG    0,1 67108864     0      1025 /memfd:pulseaudio (deleted)
chrome    46460 cdown   45r   REG   0,27   131072     0    105357 /dev/shm/.com.google.Chrome.gL8tTh (deleted)

这会列出所有st_nlink值小于 1 的打开文件。

减轻

在您的情况下,您可以通过终止进程来关闭文件句柄,如果可能的话,这是一个很好的解决方案。

如果无法做到这一点,在 Linux 上,您可以通过访问文件描述符支持的数据/proc/pid/fd并将其截断为大小 0,即使文件已被删除:

: > "/proc/pid/fd/$num"

请注意,根据您的应用程序随后对该文件描述符执行的操作,应用程序可能会对像这样从其下面更改数据感到不同程度的不满。

如果您确定文件描述符只是泄漏并且不会再次访问,那么您也可以使用gdb关闭它。首先,使用lsof -nP +L1ls -l /prod/pid/fd查找相关的文件描述符编号,然后:

% gdb -p pid --batch -ex 'call close(num)'

回答您的其他问题,尽管这不是您问题的原因:

文件[描述符]的数量是否有限?

文件描述符的数量有限,但这不是您在这里遇到的限制。 “设备上没有剩余空间”是ENOSPC,这是当您的文件系统空间不足时我们生成的。如果达到文件描述符限制,您将收到EMFILE(进程级短缺,呈现strerror为“打开的文件太多”)或ENFILE(系统级短缺,呈现strerror为“系统中打开的文件太多”)。进程级软限制可通过 进行检查ulimit -Sn,系统级限制可通过 进行查看/proc/sys/fs/file-max

答案2

只要您持有(现已删除)文件的句柄,您仍然可以访问其数据(从持有该句柄的进程)。这些数据需要一个地方来存放。

相关内容