![为什么在 inode 中使用间接指针不会产生相同的空间量?](https://linux22.com/image/130007/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%9C%A8%20inode%20%E4%B8%AD%E4%BD%BF%E7%94%A8%E9%97%B4%E6%8E%A5%E6%8C%87%E9%92%88%E4%B8%8D%E4%BC%9A%E4%BA%A7%E7%94%9F%E7%9B%B8%E5%90%8C%E7%9A%84%E7%A9%BA%E9%97%B4%E9%87%8F%EF%BC%9F.png)
我在多级分页中也遇到了同样的困惑。对于索引节点,我们有指向数据块的直接和间接指针。然而,对于小文件,我们更喜欢使用间接指针,因为它们可以为我们的目的存储更多的指针。
但是,为什么在一层按顺序存储直接指针会消耗更多的数据,而使用间接指针则消耗更少的数据呢?当然,所有指针都必须存在于文件系统中的某个位置,并且占用相同数量的空间,不是吗?这个额外的空间从哪里来?
这是我的想法的一个例子:如果我有 10 个直接指针和 2 个间接指针,每个指针分别指向 128 和 128^2 指针,那么消耗的总大小是否与 10 + 128 + 128^2 相同直接指针?如果没有,如何节省空间?
作为一个附带问题,索引节点的典型大小是多少?为什么索引节点的大小会有所不同?
答案1
inode 级别的原始层次结构大致如下:
你可以直接在 inode 中存储一个或几个块号。这意味着您要为索引节点多使用几个字节,但对于小文件,您不必分配一个完整的块,该块大部分是空的。
下一级是一个间接寻址:您分配一个块来存储块指针。 inode 中仅存储该间接块的地址。这不会以某种方式使用“更少的空间”,并且大多数文件系统,甚至是早期的文件系统,都是这样工作的(在索引节点/文件名附近有一个指针,该指针指向一个块,该块存储文件的块号)。
但是当这个区块的空间用完时你该怎么办?您必须分配另一个块,但是您在哪里存储对此块的引用?您可以只将这些引用添加到索引节点,但为了存储更大的文件,索引节点会变大。并且您需要较小的索引节点,以便尽可能多的索引节点可以放入单个块中(更少的磁盘访问来读取更多的索引节点)。
因此,您使用两级间接块:您只需添加一指向 inode 的指针,那么就有一个完整的块来存储指向间接块的指针,间接块存储文件本身的块地址。
依此类推,您可以添加更高级别的间接块,或者在某个阶段停止,直到达到所需结构的文件可能的最大大小。
因此,重点不是“总共使用更少的空间”,而是“使用一种有效使用块的方案来实现文件大小的预期分布,即许多小文件,一些较大的文件和很少的大文件”。
另一方面,页表的工作方式却截然不同。
编辑
回答评论中的问题:
数据块具有固定大小(最初为 512 字节,IIRC),它是底层硬盘块大小的倍数。所以数据块大小不能“减少”。
正如我在上面尝试描述的,让 inode 不占用太多空间的全部目的是使索引节点访问速度更快(或者,让缓存 inode 占用更少的内存——当时,当带有 inode 的 unix 文件系统被发明时,计算机有一个很多内存比今天少)。它是不是关于以某种方式总共节省空间。正如您自己所说,所有内容都必须存储在某个地方,如果它没有使用位置 X 的空间,它将使用位置 Y 的空间。
仅仅向 inode 添加可变数量的块指针是不切实际的,因为 inode 必须占用固定量的空间 - 您要使用 inode 编号来计算块地址以及 inode 信息所在的块内的偏移量存储。如果每个 inode 都有不同的大小,则无法做到这一点。所以一定有一些间接形式。
页表的工作方式不同,因为硬件以不同的方式实现它们 - 就是这样。层次结构具有固定的深度,始终相同(尽管有时是可配置的)。虽然从磁盘读取块的速度很慢,但这对于页表来说并不重要。因此设计问题完全不同。