use*_*134 5 filesystems disk-usage
所以,长话短说,我写了一个(python)程序,它打开了很多文件,在其中写入数据,然后删除了文件,但没有正确关闭文件句柄。一段时间后,该程序因磁盘空间不足而停止。
bash 中的自动完成失败cannot create temp file for here-document: No space left on device"
,并lsof -nP +L1
显示大量不再存在的文件。
杀死我的程序后,所有文件句柄都关闭了,磁盘空间再次“空闲”,一切正常。
为什么会这样?磁盘空间没有被物理填满。还是文件句柄数量有限?
Chr*_*own 21
在 Unix 中删除文件只是删除对其数据的命名引用(因此系统调用名称为unlink
/ unlinkat
,而不是delete
)。为了释放数据本身,必须没有其他对它的引用。可以通过以下几种方式获取参考:
st_nlink
必须为 0)——这可能在硬链接时发生。否则,我们会在仍有办法从文件系统访问数据时删除数据。struct file
'sf_count
必须为 0)。否则,数据仍然可以通过读取或写入文件句柄(或/proc/pid/fd
在 Linux 上)来访问或改变,我们需要在某个地方继续存储它。一旦满足这两个条件,数据就有资格被释放。由于您的情况违反了条件#2 - 您仍然有打开的文件句柄 - 数据继续存储在磁盘上(因为它无处可去),直到文件句柄关闭。
一些程序甚至使用它来简化清理他们的数据。例如,假设一个程序需要将一些大数据存储在磁盘上用于中间工作,但不需要与其他人共享。如果它打开然后立即删除该文件,它可以使用它而不必担心确保它们在退出时被清除——打开的文件描述符引用计数在退出时自然会降为 0 close(fd)
,并且相关空间将被释放程序是否正常退出。
仍由文件描述符打开的已删除文件可以使用 找到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)
Run Code Online (Sandbox Code Playgroud)
这列出了st_nlink
值小于 1 的所有打开的文件。
在您的情况下,您可以通过终止进程来关闭文件句柄,如果可能,这是一个很好的解决方案。
在不可能的情况下,在 Linux 上,您可以通过访问文件描述符支持的数据/proc/pid/fd
并将其截断为大小 0,即使文件已被删除:
: > "/proc/pid/fd/$num"
Run Code Online (Sandbox Code Playgroud)
请注意,根据您的应用程序对该文件描述符的处理方式,应用程序可能会对像这样从其下更改数据感到不同程度的不满。
如果您确定文件描述符只是泄漏并且不会再次被访问,那么您也可以使用gdb
关闭它。首先,使用lsof -nP +L1
或ls -l /prod/pid/fd
找到相关的文件描述符编号,然后:
% gdb -p pid --batch -ex 'call close(num)'
Run Code Online (Sandbox Code Playgroud)
要回答您的其他问题,尽管这不是您问题的原因:
文件[描述符]的数量有限制吗?
文件描述符的数量是有限的,但这不是您在这里达到的限制。“设备上没有剩余空间”是ENOSPC
,这是我们在您的文件系统空间不足时生成的内容。如果您达到文件描述符限制,您将收到EMFILE
(进程级短缺,表现strerror
为“打开的文件太多”)或ENFILE
(系统级短缺,表现strerror
为“系统中打开的文件太多”)。进程级软限制可以用 来检查ulimit -Sn
,系统级限制可以在 中查看/proc/sys/fs/file-max
。