为什么在以前很大的小目录中“ls”需要很长时间?如何解决这个问题?

为什么在以前很大的小目录中“ls”需要很长时间?如何解决这个问题?

我正在运行 Arch Linux,并使用 ext4 文件系统。

当我ls在一个现在实际上很小但曾经很大的目录中运行时 - 它会挂起一段时间。但下次我运行它时,它几乎是瞬时的。

我尝试这样做:

strace ls

但老实说我不知道​​如何调试输出。如果需要的话我可以发布它,尽管它有 100 多行长。

而且,不,我没有使用任何别名。

$ type ls
ls is hashed (/usr/bin/ls)

$ df .
Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda9      209460908 60427980 138323220  31% /home

答案1

一个曾经很大的目录可能仍然有很多分配给目录条目的块(=该目录中文件和子目录的名称和索引节点号),尽管现在几乎所有这些块都被标记为已删除。

创建新目录时,只会为目录条目分配最小数量的空间。随着越来越多的文件被添加,新的块被分配来根据需要保存目录条目。但是,当文件被删除时,ext4文件系统不会合并目录条目并释放现在不需要的目录元数据块,因为假设可能很快就会再次需要它们。

您可能必须卸载文件系统并e2fsck -C0 -f -D /dev/sda9在其上运行 a 来优化目录,以释放额外的目录元数据块并将现有目录条目合并到更小的空间。

由于它是您的/home文件系统,因此您可以通过确保所有常规用户帐户都已注销,然后以 root 身份本地登录(通常在文本控制台上)来完成此操作。如果umount /home在这种情况下报告文件系统正忙,您可以使用 来fuser -m /dev/sda9识别阻止您卸载的进程/home。如果它们是旧用户会话的残余物,您可能可以直接杀死它们;但如果它们属于服务,您可能希望以受控方式停止这些服务。

进行此类主要维护的另一种经典方法是/home将系统启动到单用户/紧急模式。在使用 的发行版上systemd,引导选项systemd.unit=emergency.target应该可以做到这一点。

正如其他人提到的,有一个更简单的解决方案,如果保留目录的时间戳并不重要,并且问题目录不是它所在文件系统的根目录:在“臃肿”的目录旁边创建一个新目录,将所有文件移动到新目录,删除旧目录,然后将新目录重命名为具有相同的名称就像旧的那样。例如,如果/directory/A是有问题的:

mkdir /directory/B
mv /directory/A/* /directory/B/      # regular files and sub-directories
mv /directory/A/.??* /directory/B/   # hidden files/dirs too
rmdir /directory/A
mv /directory/B /directory/A

当然,如果该目录正在被任何服务使用,最好先停止这些服务。

答案2

出于好奇,让我们尝试重现这一点:

$ mkdir test
$ cd test
$ time ls   # Check initial speed of ls
real    0m0,002s
$ stat .    # Check initial size of directory
  File: .
  Size: 4096        Blocks: 8          IO Block: 4096   directory
  ...
$ seq 1 1000000 | xargs touch    # Create lot of files
$ echo 3 | sudo tee /proc/sys/vm/drop_caches   # Clear cache
$ time ls > /dev/null
real    0m1.588s
$ stat .                        # Check size of directory when files are there
  File: .
  Size: 22925312    Blocks: 44776      IO Block: 4096   directory

好的,现在我们有了一个大目录。让我们删除这些文件,看看会发生什么:

$ ls | xargs rm   # To avoid too long argument list
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
$ time ls > /dev/null
real    0m1.242s
$ stat .
 File: .
 Size: 22925312     Blocks: 44776      IO Block: 4096   directory

所以是的,目录的分配大小确实很大,这确实导致缓慢ls,就像 telcoM 的答案也指出的那样。

如果只是单个目录出现问题,有一个更简单的解决方案,不需要卸载或 root 访问权限:只需创建一个新目录,将剩余文件移至其中并删除臃肿的文件即可。

相关内容