在x86架构上,Linux内核的默认内存页面大小为4KB,我想知道这是如何计算出来的,以及为什么选择这个大小?
在x86架构上,Linux内核的默认内存页面大小为4KB,我想知道这是如何计算出来的,以及为什么选择这个大小?
默认页面大小由CPU的内存管理单元(MMU)支持的大小确定。在32位保护模式下,x86支持两种页面:
并非所有的x86处理器都支持大页面。需要具备页面大小扩展(PSE)功能的CPU。这排除了早期的奔腾处理器。几乎所有当前的x86 CPU都实现了它。
4 KiB也是其他架构中广泛使用的页面粒度。有人可能会认为这个大小来自于将32位虚拟地址划分为两个10位索引和剩余的12位给出4 KiB页面大小。
第一个支持页面虚拟内存技术的英特尔处理器是Intel 80386。该处理器支持单个页面大小,4 KB。由于它是在1985年发布的,我们必须回到那个时期才能理解为什么英特尔选择了这个特定的页面大小。
Atlas是第一台支持页面大小为3 KB 的计算机,它对虚拟内存设计产生了深远影响并激发了相关研究。该系统设计于1958-1962年间。有趣的是,尽管80386是大约20年后设计的,并且计算机(以及它们运行的工作负载)在这段时间内发生了巨大变化,但它支持的页面大小与Atlas支持的页面大小相当接近!事实上,当时许多计算机使用的页面大小范围在0.5-5 KB之间。当时的研究人员实际上花费了大量精力研究虚拟内存系统(分页和分段)。
一个重要的问题是:什么是最佳页面大小?在60年代和70年代,有大量的研究尝试研究和理解页面大小对应用程序性能的影响,并提出建议或提供指导如何选择页面大小。肯定有一些未发表的论文。据我所知,这包括英特尔的文件,其中说:“...因此,页面大小应为4 KB。”但影响或与页面大小相互作用的因素以及选择页面大小(或多个页面大小)的过程是众所周知的,这就是我将在这篇文章中基本讨论的内容。我还将特别解释为什么4 KB的页面大小是合理的。N
* P
),物理地址的大小为log2(N
* F
)。VA的一些位表示页面内的偏移量,而其他位表示页面号,使用映射设备标识页面。N
* P
或N
* F
,以较小者为准。这是很多选择。PN
,OFF
)。翻译过程应尽可能高效。对于程序员来说,页面内的字节在地址空间中连续是方便的。通过在单个地址上进行简单算术运算,即数据结构的基地址,可以计算出多字节数据结构内项目的地址。这可以通过使用虚拟地址的最低有效log2(N
)位(向上取整)表示偏移量,其余位表示页面号来实现。N
不是2的幂,则偏移量和页码之间会共享一些位,具体取决于这些位的值。将N
设置为2的幂次方可以避免这种复杂情况。因此,使用2的幂次方作为页面大小会更加简洁。所有支持分页的真实处理器都使用2的幂次方作为页面大小(尽管可寻址单位可能不是8位),这是有道理的。但说实话,现在技术已经发展到了令人难以置信的地步,N
是否是2的幂次方可能对性能或其他感兴趣的度量标准没有任何可衡量的影响。事实上,在未来需要更大的页面大小时,可能会出现一些不是2的幂次方的页面大小更好的情况。但到目前为止,还没有发生过。我想表达的观点是,使页面大小不是2的幂次方的设计选项不应该自动被忽视。我认为这是未来虚拟内存系统研究的一个好机会。几个月前,英特尔被授予了一项专利,该专利提出了一个默认页面大小为64 KB的系统,但同时支持4 KB页面(和其他IA-32e页面大小)以实现向后兼容性。我引用专利中的话:
由于支持将64 KB页面映射到4 KB子页面,VA64直接支持所有当前定义的4 KB页面操作,包括每个4 KB页面的独立保护位和任意4 KB对齐地址映射。即使操作系统内核以64 KB为单位分配内存,VA64也支持在4 KB边界上进行OS内核页面管理。由于支持大页面,VA64支持现有分页系统(例如英特尔公司的IA-32e分页系统)支持的虚拟地址范围的所有页面划分。因此,VA64支持与4 KB页面Windows®操作系统内核一起工作的应用程序和硬件设备,同时在可以使用64 KB页面时充分利用64 KB页面。除了专利中所写的内容,我对VA64分页系统一无所知。网上没有任何相关信息。我猜我们很快就会知道更多。
Denning, P.J. (1970). 虚拟内存. ACM计算机调查杂志 第2卷第3期,153-189。
Gelenbe, E., Tiberio, P., & Boekhorst, J. C. A. (1973). 需求分页系统中的页面大小. Acta Informatica,第3卷第1期,1-23。
Alanko, T. O., & Verkamo, A. I. (1983). 分段、分页和虚拟内存中的最佳页面大小。性能评估,第3卷第1期,13-33。
Corbató,F. J.和Vyssotsky,V. A。(1965)。Multics系统的介绍和概述。在1965年11月30日至12月1日秋季联合计算机会议第一部分的论文集中(第185-196页)。
(1) 实际上一个虚拟页的大小可以是页面帧大小的倍数,但我们不深入讨论这个。
(2) 我们可以概括公式,使用术语“字”来指代最小可寻址内存单元而非字节,但这在这里并不重要。
(3) 根据编程语言的不同,也许不是程序员,而是编译器、链接器、汇编器以及与二进制代码相关的工具。
(4) 设计支持同时使用分页和非分页的系统当然是可能的,从而潜在地支持多个分配单元,但我们不深入讨论这个。
32位体系结构中4KB普通页面大小的设计实际上非常有趣 :)
我想补充一个额外的答案来说明为什么这是合理的。
x86使用“2级页表”将虚拟内存地址转换为物理内存地址。
因此,假设页面目录和页面表都包含2x个条目,并且页面大小为2y字节。为了充分利用232个地址,我们有:
2x × 2x × 2y = 232 ⇒ 2x + y = 32
每个页面目录/表中的条目占用4个字节(32位),因此:
2y/4 = 2x ⇒ y - 2 = x
因此y=12,页面大小以字节为单位将是2y = 212 = 4KB。
那么“1级页表”呢?这很有趣,因为在逻辑上我们可以使用单个页表进行地址查找。
假设页面目录包含2x个条目,每个条目将地址映射到相应的页面,页面大小为2y字节。
同样,为了充分利用232个地址,我们需要:
2x × 2y = 232 ⇒ x + y = 32
和:
2y/4 = 2x ⇒ y - 2 = x
我们得到y=17,页面大小是2y = 217 = 128KB。
我们也可以说,在“2级页表”版本中,页面目录和页面表可能具有不同的大小。但这意味着我们将使用更大的页面目录,它将占用超过一个内存页面。可惜的是,每当生成新的用户进程时,为了其自己的页面目录,操作系统必须分配连续的页面,这不是设计上的优雅。
我添加了这个答案/评论,因为sleepsort的计算非常有趣,我必须将其添加到我的网页上(当然要注明来源)。
关于如何以编程方式计算页面大小的(可能的)答案可以在这里找到。正如sleepsort所提到的那样,它的计算方式非常有趣。我对x86_64也做了同样的尝试,但结果并不是我所期望的。
然而,在进一步阅读x86_64内存管理后,我发现对于64位英特尔处理器,其中16位未被使用,留下48位供我们计算。
9位用于内存树分支,
每个分支另外9位,
这里再加上另外9位用于分支,
最后还有9位用于最后一个分支的叶子节点。
所以每个内存页中的每个地址有12位,即48-36=12位。 212=4096,正如sleepsort之前提到的。
我只是想知道这个架构经过了多少次传递,是3次还是4次(如果有人能解释一下)
根据sleepsort的计算:
2x * 2x * 2x * 2x * 2y = 248
4x + y = 48
这次每个地址有8字节(8字节*8位/字节=64位)
2y / 23 = 2x
y - 3 = x
填入上一个方程式:
4(y - 3) + y = 48
4y - 12 + y = 48
5y = 60
y = 12
因为2y表示页面大小,所以大小= 212 = 4096字节
让我想起了“Linux中的巨大页面”这个问题?