如何找到已删除但仍在应用程序中打开的大文件?即使某个进程打开了这样的文件,如何删除它?
情况是我们正在运行一个进程,该进程正在以惊人的速度填满日志文件。我知道原因,我可以解决它。在那之前,我想在不关闭进程的情况下 rm 或清空日志文件。
简单地执行rm output.log
只会删除对该文件的引用,但它会继续占用磁盘上的空间,直到进程终止。更糟糕的是:在rm
ing 之后,我现在无法找到文件在哪里或有多大!有没有办法找到该文件,并可能清空它,即使它仍然在另一个进程中打开?
我特指基于 Linux 的操作系统,例如 Debian 或 RHEL。
答案1
如果无法终止应用程序,可以截断而不是删除日志文件来回收空间。如果文件不是以追加模式(使用O_APPEND
)打开的,那么下次应用程序写入该文件时,该文件将显示为与以前一样大(尽管前导部分稀疏并且看起来好像包含 NUL 字节),但空间将被回收(但这不适用于 Apple OS/X 上不支持稀疏文件的 HFS+ 文件系统)。
截断它:
: > /path/to/the/file.log
如果它已经被删除,在 Linux 上,您仍然可以通过执行以下操作来截断它:
: > "/proc/$pid/fd/$fd"
$pid
打开文件的进程的进程 ID 以及它$fd
在其下打开的一个文件描述符(您可以使用lsof -p "$pid"
.
如果您不知道 pid,并且正在查找已删除的文件,您可以执行以下操作:
lsof -nP | grep '(deleted)'
lsof -nP +L1
,正如@user75021所述是一个更好的(更可靠、更便携的)选项(列出链接少于 1 个的文件)。
或者(在 Linux 上):
find /proc/*/fd -ls | grep '(deleted)'
或者用以下命令找到大的zsh
:
ls -ld /proc/*/fd/*(-.LM+1l0)
如果应用程序是动态链接的,另一种方法是附加一个调试器并使其调用,close(fd)
然后调用一个新的open("the-file", ....)
.
答案2
在此处查看快速入门:lsof
快速开始
我很惊讶没有人提到 lsof 快速入门文件(包含在 lsof 中)。 “3.a”部分展示了如何查找打开的、未链接的文件:
lsof -a +L1 *mountpoint*
例如:
[root@enterprise ~]# lsof -a +L1 /tmp
COMMAND PID USER FD TYPE DEVICE SIZE NLINK NODE NAME
httpd 2357 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
mysqld 2588 mysql 4u REG 253,17 52 0 1495 /tmp/ibY0cXCd (deleted)
mysqld 2588 mysql 5u REG 253,17 1048 0 1496 /tmp/ibOrELhG (deleted)
mysqld 2588 mysql 6u REG 253,17 0 0 1497 /tmp/ibmDFAW8 (deleted)
mysqld 2588 mysql 7u REG 253,17 0 0 11387 /tmp/ib2CSACB (deleted)
mysqld 2588 mysql 11u REG 253,17 0 0 11388 /tmp/ibQpoZ94 (deleted)
httpd 3457 root 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8437 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8438 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8439 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8440 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8441 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8442 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8443 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 8444 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 16990 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 19595 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 27495 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 28142 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd 31478 apache 29u REG 253,17 3926560 0 1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
答案3
实际上取决于文件系统驱动程序自由的分配的空间,通常只会发生一次全部引用该文件的文件描述符被释放。因此,除非您让应用程序关闭文件,否则您无法真正回收空间。这意味着要么终止它,要么在调试器中“稍微”使用它(例如关闭文件并确保它不会再次打开/写入,或者/dev/null
改为打开)。或者你可以破解内核,但我建议不要这样做。
按照 Stephane 的建议截断文件可能会有所帮助,但真正的结果还取决于您的文件系统(例如,在任何情况下,只有在关闭文件后,预分配的块才可能被释放)。
这种行为背后的基本原理是,内核不知道如何处理针对此类文件的数据请求(读和写,但读实际上更关键)。
答案4
您可以使用以下命令清空该日志文件,而不是删除您现在无法终止的进程所保存的文件echo
:
echo -n > /var/log/myapp.log
您可以使用命令检查之后df
- “已用字节”列将是减少。