我正在运行 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 访问权限:只需创建一个新目录,将剩余文件移至其中并删除臃肿的文件即可。