39

x86 架构上 Linux 内核的默认内存页面大小为 4 KB,我想知道这是如何计算的,为什么?

4

6 回答 6

45

默认页面大小由 CPU 的 MMU(内存管理单元)支持的大小固定。在 32 位保护模式下,x86 支持两种页面:

  • 正常的,4 KiB
  • 巨大的,4 MiB

并非所有 x86 处理器都支持大页面。需要有一个具有页面大小扩展 (PSE) 功能的 CPU。这不包括奔腾之前的处理器。几乎所有当前一代的 x86 CPU 都实现了它。

4 KiB 也是其他架构中广泛流行的页面粒度。有人可能会争辩说,这个大小来自于将 32 位虚拟地址划分为页面目录/表中的两个 10 位索引,其余 12 位给出 4 KiB 页面大小。

于 2012-07-18T14:41:16.807 回答
26

32位架构的4KB正常页面大小的设计其实很有意思:)

我想添加一个额外的答案来证明为什么它是合理的。

x86 使用“2 级页表”将虚拟内存地址转换为物理内存地址。

所以假设页目录和页表都包含在此处输入图像描述条目,并且页大小是在此处输入图像描述字节。为了充分利用在此处输入图像描述地址,我们有:

在此处输入图像描述

页目录/表中的每个条目占用 4 个字节(32 位),因此:

在此处输入图像描述

因此 y = 12,以字节为单位的页面大小将为在此处输入图像描述= 在此处输入图像描述= 4KB。


那么'1级页表'呢?这很有趣,因为从逻辑上讲,我们可以使用单个页表进行地址查找。

假设页目录包含在此处输入图像描述条目,每个条目映射一个地址到对应的页,页大小为在此处输入图像描述字节。

同样,为了充分利用在此处输入图像描述地址,我们需要:

在此处输入图像描述

和:

在此处输入图像描述

我们得到 y = 17,页面大小为在此处输入图像描述= 在此处输入图像描述= 128KB。


我们也可能会争辩说,在“2 级页表”版本中,页目录和页表可能有不同的大小。然而,这意味着我们将使用更大的页面目录,这将占用一个以上的内存页面。可悲的是,每次产生新的用户进程时,操作系统必须为其自己的页面目录分配连续的页面,这在设计上并不优雅。

于 2014-06-30T12:39:10.657 回答
18

介绍

第一个支持分页虚拟内存技术的 Intel 处理器是Intel 80386。处理器支持单一页面大小,4 KB。自从它在 1985 年发布以来,我们必须回到那个时期来理解英特尔为什么选择那个特定的页面大小。

Atlas是第一台支持分页的计算机,页面大小为 3 KB,对虚拟内存的设计和相关研究产生了深远的影响。该系统是在 1958-1962 年间设计的。有趣的是,80386 支持的页面大小有点接近 Atlas 支持的页面大小,尽管 80386 是在大约 20 年后设计的,并且计算机(以及它们运行的​​工作负载)在那个时期发生了根本性的变化。时间!事实上,那个时期的许多计算机使用的页面大小在 0.5-5 KB 之间。当时的研究人员实际上花费了大量精力研究虚拟内存系统(分页和分段)。

最大的问题之一是:最佳页面大小是多少?在 60 和 70 年代发表了大量的作品,试图研究和理解页面大小对应用程序性能的影响,并推荐或提供如何选择页面大小的指南。肯定有许多论文从未发表过。据我所知,这包括来自英特尔的文档,上面写着“......因此,页面大小应为 4 KB”。但是影响页面大小或与页面大小交互的因素以及选择页面大小(或多个页面大小)的过程是众所周知的,这就是我将在此答案中基本讨论的内容。我还将特别解释为什么 4 KB 的页面大小是合理的。

页面大小问题

在分页方法中,物理内存被组织为一系列连续的内存区域,称为页框,它们具有相同的大小(这是分页1的定义特征)。每个页框都可以映射到相同大小的虚拟地址空间块,称为虚拟页。

假设一个页面由N字节2组成(这意味着N根据定义,一个页框的大小也是字节)并考虑一个由P页面组成的虚拟地址空间(即,页码是 {0,1,2,... , P- 1} 并且虚拟地址的总数是N* P)。还假设物理地址空间由F页框组成(即页框号为 {0, 1, 2, ..., F- 1},物理地址的总数为N* F)。

给定一个虚拟地址VA,需要一种机制(映射设备)来确定物理地址,PA它被映射到,或者如果它没有被映射,则应该引发页面错误。映射设备使用存储在某处的数据结构(页表)来执行映射。对于每个分配的虚拟页面,该表中应该有一个条目,该条目描述页面的映射方式以及可能的一些附加属性(例如保护属性)。如您所见,页表条目的设计与页面大小相互作用。稍后我将讨论 Intel 80386 中页表项的设计。

虚拟地址的大小为 log 2 ( N* P),物理地址的大小为 log 2 ( N* F)。的一些位VA将表示页面内的偏移量,而其他位将表示页码,它使用映射设备标识页面。

页面大小有多少种选择?好吧,它可以小到一个字节,最多N*PN* F,以较小者为准。这是很多选择。

Page Size 是 2 的幂很方便

虚拟地址 ,VA相当于一对页码和偏移量 ( PN, OFF)。翻译过程应尽可能高效。对于程序员3来说,让一个页面中的字节在地址空间中是连续的是很方便的。这样,一个多字节数据结构中的项目的地址可以通过对单个地址的简单算术来计算,这将构成数据结构的基地址。这可以通过使用虚拟地址的最低有效 log 2 ( N) 位(向上舍入)来表示偏移量和其余位来表示页码来实现。

如果N不是 2 的幂,则偏移量和页码之间将共享一些位,具体取决于这些位的值。通过N2 的幂,不存在这种复杂性。因此,使用 2 的幂的页面大小会很巧妙。所有支持分页的实际处理器都使用 2 的幂的页面大小(尽管可寻址单元可能不是 8 位),这是有道理的。但老实说,目前尚不清楚这是否真的重要。使用当今的技术,无论N是 2 的幂可能对性能或任何其他感兴趣的指标没有任何可衡量的影响。事实上,在未来需要越来越大的页面大小时,可能会出现一些不是 2 的幂的页面大小更好的情况。但到目前为止,这还没有发生。我在这里要说明的一点是,不应自动取消使页面大小不是幂 2 的设计选项。我相信这是研究未来虚拟内存系统的好机会。

无论如何,请记住 4 KB 页面的选择是在 80 年代做出的,页面大小的如此微小的变化(理论上和实验上)被证明是无关紧要的。因此,2 次幂页面大小的便利性占了上风。这会以指数方式减少要考虑的页面大小的数量。但是我们仍然有很多选择。

偏爱较小的页面大小

由于映射设备工作在页级别,所以从操作系统的角度来看,分配的单位是虚拟页4。即使应用程序只需要分配 1 个字节,它仍然必须告诉操作系统为该 1 个字节分配整个虚拟页面。这个问题称为内部碎片. 每个应用程序(甚至可能是应用程序的每个组件)都有自己的虚拟地址空间,它从该空间以页面大小的块分配内存。每个应用程序不希望为它分配的单个对象使用单个页面,而是在分配更多页面之前从同一页面分配尽可能多的对象。然而,由于页面属性在页面级别起作用,同一个应用程序可能会使用多个用户模式内存管理器(例如使用多个 C/C++ 运行时时),并且应用程序很难共享它们不使用的部分页面对于其他应用程序,系统中的许多页面可能会出现内部碎片。使用较小的页面大小可以帮助减少浪费的物理(整个系统)和虚拟(每个进程)内存的数量。

此外,通常应用程序在其生命周期中会经历多个阶段,在不同阶段它们表现出不同的内存需求。例如,如果页面大小为 16 KB,但许多应用程序的许多阶段可能只需要更少的 10 KB,那么将会浪费大量物理内存,这可能会导致内存不足的情况如果支持较小的页面大小(例如 8 或 4 KB),则可以避免。

较小的页面大小更适合处理写时复制软页面错误,因为页面越小,创建它的副本所需的时间就越少。对于极小的页面大小,这可能不会产生任何可测量的差异,具体取决于内存总线带宽。

70 年代计算机中可用的典型物理内存量在 10 或 100 KB 范围内。拥有数百 KB 或更大的页面大小是没有意义的。事实上,当时的应用程序工作集通常只有几个或几十个 KB。因此,即使只有 16 KB 的页面大小也不太实用,因为只有几个页面可能会消耗所有可用的物理内存。页面大小应与物理内存量一致。这个论点当然可以应用于今天的系统(例如,拥有 128 GB 的页面是没有意义的)。

所以考虑到70 年代和 80 年代初的工作集大小和物理内存可用性,页面大小应该是 2 的幂,范围为 2 0 -2 14。很酷,现在我们只有 15 个选项可供选择。

偏爱更大的页面大小

我们也可以争辩说更大的页面大小更好。对于相同的工作集,较小的页面大小意味着每个应用程序的页面数量较多,这需要页表条目才能启用转换。无论页表的结构如何,这基本上都需要更大的页表(尽管确切的开销取决于页表条目本身的设计,我将在后面讨论)。想象一下,例如 4 字节的页面和数十 KB 的典型工作集。然后大部分物理内存实际上将被分配来保存页表,而不是数据。将页表分页到辅助存储会导致单个内存引用出现双页错误,这对性能来说绝对是可怕的。这样的设计显然是荒谬的。

从本质上讲,页面大小不应该(很多)小于可能的最小工作集大小。这立即排除了大小为 2 0 -2 6的页面,为我们留下了 8 个选项。70 年代和 80 年代初研究页面大小的论文大多只研究这 8 个选项。

还有另一个原因使更大的页面大小更有利。虚拟内存的好处之一是能够透明地使用除主内存之外的辅助存储来保存易失性数据。但是,辅助存储设备是机械的,并且在批量传输时性能最佳。这实际上更像是一个指导方针,我们不应该排除任何页面大小。存在具有不同设计和特性的设备,最终,批量传输的性能优势将在某个时候达到饱和。但在衡量页面大小对性能的影响时,肯定需要考虑到这一点。如果正在考虑的应用程序类型表现出很少的空间局部性,那么较小的页面大小仍然是可取的,因为将额外的字节复制到磁盘或从磁盘复制并不是完全免费的。

空间参考位置鼓励使用某些页面大小。对于非常小的页面大小,页面中的所有字节很可能会在很短的时间内被使用。随着页面大小变大,不太可能使用的字节数会增加。但是,对于非常大的页面,所有工作集都可能适合少数页面,而与位置无关。因此,为了最大限度地减少页面错误的数量,页面大小应该太小或太大,但不能介于两者之间。但最终,这会因一个应用程序而异。新兴的编程范式,例如面向对象编程和函数式编程,由于链接结构的广泛使用以及不同应用程序相互交互的方式,多线程等技术实际上可能会降低空间局部性。较大的页面大小更适合减少页面错误的数量。但是,较小的页面大小可能更适合多个应用程序之间共享的内存,以减少共享页面的内部碎片。实验还表明,可以保存在主存储器中的页框数量与页面错误的数量相关,有利于更小的页面大小。

对 TLB 的需求在当时得到了广泛认可。英特尔在他们的专利中称它们为页面缓存(不确定英特尔是否是第一个使用该术语的)。快速 TLB 非常重要,因为地址转换是执行指令的关键路径。为了使它们尽可能快,它们应该做得很小,但是它们只能缓存少量的页表条目。这促使使用更大的页面大小。

在寻找最佳页面大小时,事实证明没有。当时就知道需要支持多种页面大小。事实上,1965 年设计的 Multics 系统支持 64 或 1,024 字的页面(一个字的大小为 36 位)。在不同的场景中,2 7 -2 14范围内的页面大小在经验和理论上都是最佳的。英特尔必须观察到 4 KB 页面可以为其客户在 80 年代使用的应用程序带来最佳的平均性能。对于今天的计算机和应用程序,页面大小的微小差异并没有像 70 年代和 80 年代那样产生太大影响。

Intel 80386的页表项设计

页目录项和页表项的设计在英特尔的一项专利中进行了详细讨论。这很重要,因为页表条目的大小和页表的整体结构在许多关于页大小的研究中都被考虑在内,因为它们都相互影响。我不想更详细地讨论这个问题,以保持答案简短。

近期的页面大小

几个月前,英特尔获得了一项专利,该专利显然提出了一个默认页面大小为 64 KB 的系统,但同时支持 4 KB 页面(和其他 IA-32e 页面大小)以实现向后兼容性。我引用专利:

由于支持将 64 KB 页映射到 4 KB 子页,VA64 直接支持当前定义的所有 4 KB 页上的操作,包括每 4 KB 页的独立保护位和任意 4 KB 对齐地址映射。VA64 还支持 4 KB 边界上的操作系统内核页面管理,即使操作系统内核以 64 KB 为单位分配内存。由于支持大页面,VA64 支持将虚拟地址范围划分为现有分页系统(例如英特尔公司的 IA-32e 分页系统)支持的页面。因此,VA64 支持使用 4 KB 页面 Windows® OS 内核的应用程序和硬件设备,同时在可以使用 64 KB 页面时充分利用 64 KB 页面。

VA64 的能力可以逐渐被操作系统内核采用,而不是要求它们都在第一代支持 VA64 的操作系统内核中得到支持。例如,支持 VA64 的操作系统内核可以通过将所有页面映射到当前大小(例如,英特尔公司的 IA-32e 分页系统中的 4 KB/2 GB/1 TB)开始,但会更改为新的页表格式。在页表格式改变后,操作系统内核可以修改为以 64 KB 为单位映射虚拟内存,并在其空闲列表中更改为存储 64 KB 页面。然后,只要对齐和保护允许,操作系统内核就可以开始使用 64 KB 页面,并添加对其他 VA64 功能的支持。

除了专利中的内容外,我对 VA64 寻呼系统一无所知。互联网上的任何地方都没有任何内容。我想我们很快就会知道更多。

选定的参考文献

丹宁,PJ(1970)。虚拟内存。ACM 计算调查第 2 卷第 3 期,153-189。

Gelenbe, E.、Tiberio, P. 和 Boekhorst, JCA (1973)。按需分页系统中的页面大小。信息学报,3(1),1-23。

Alanko, TO 和 Verkamo, AI (1983)。虚拟内存中的分段、分页和最佳页面大小。绩效评估,3(1),13-33。

科尔巴托,FJ 和维索茨基,弗吉尼亚州(1965 年)。Multics系统的介绍和概述。在 1965 年 11 月 30 日——1965 年 12 月 1 日的会议记录中,秋季联合计算机会议,第一部分(第 185-196 页)。


脚注

(1)实际上单个虚拟页面的大小可以是页框大小的倍数,但我们不要去那里。

(2) 我们可以概括公式并使用术语“字”来指代内存的最小可寻址单元而不是字节,但这并不重要。

(3) 也许不是程序员,取决于编程语言,而是编译器、链接器、汇编器和使用二进制代码的工具。

(4) 当然可以设计一个同时支持分页和非分页的系统,从而可能支持多个分配单元,但我们不要去那里。

于 2018-04-26T02:32:53.250 回答
12

这取决于处理器架构

在许多体系结构上,默认页面大小为 4 KB。一般可以通过切换到巨页模式来增加(有时很多,比如AMD64的1GB) 。这允许页表更小,从而可以提高性能。

于 2012-07-18T14:37:02.103 回答
0

我从维基百科文章中得到这个,我引用:

页大小通常由处理器架构决定

看看下面的文章:

http://en.wikipedia.org/wiki/Page_(computer_memory)

于 2012-07-18T14:36:12.037 回答
0

我添加这个答案/评论是因为 sleepsort 的计算非常有趣,我必须将它添加到我的网页中(当然要提到来源)。可以在此处找到如何以编程方式计算页面大小的问题的(可能)答案。sleepsort 提到的计算方式非常有趣。我对 x86_64 做了同样的事情,结果出乎我的意料。然而进一步阅读内存管理 x86_64我发现对于 64 位的英特尔,16 位没有使用,留给我们计算 48 位。9 位用于内存树分支,每个分支另外 9 位,这里另外 9 位用于分支,最后 9 位用于最后一个分支的叶子。因此,内存页中每个地址的 48 - 36 = 12 位。2^12 = 4096,就像 sleepsort 之前提到的那样。我只是想知道这个架构有多少通过,3 或 4(如果有人能解释的话)遵循 sleepsort 的计算:

2^x * 2^x * 2^x * 2^x * 2^y = 2^48
4x + y = 48

this time we have 8 bytes for each address (8 bytes * 8 bits / byte = 64 bits)

2^y / 2^3 = 2^x
y - 3 = x
filled in in previous equation:

4(y - 3) + y = 48
4y - 12 + y = 48
5y = 60
y = 12
because 2^y represents the pagesize, the size = 2^12 = 4096 bytes

让我问“Linux 中的那些大页面怎么样”?

于 2017-08-09T10:26:50.743 回答