虚拟地址空间中的页面大小是如何确定的?

Joh*_*ino 50 linux kernel memory hardware

Linux 使用虚拟内存系统,其中所有地址都是虚拟地址而不是物理地址。这些虚拟地址由处理器转换为物理地址。

为了使这种转换更容易,虚拟和物理内存被划分为页面。这些页面中的每一个都有一个唯一的编号;页框编号。

有些页面大小可以是 2 KB、4 KB 等。但是这个页面大小数字是如何确定的?它是否受架构大小的影响?例如,32 位总线将有 4 GB 地址空间。

slm*_*slm 71

您可以通过以下getconf命令查询系统的配置来找出系统的默认页面大小:

$ getconf PAGE_SIZE
4096
Run Code Online (Sandbox Code Playgroud)

或者

$ getconf PAGESIZE
4096
Run Code Online (Sandbox Code Playgroud)

注意:上述单位通常以字节为单位,因此 4096 等于 4096 字节或 4kB。

这是在 Linux 内核的源代码中硬连线的:

例子

$ more /usr/src/kernels/3.13.9-100.fc19.x86_64/include/asm-generic/page.h
...
...
/* PAGE_SHIFT determines the page size */

#define PAGE_SHIFT  12
#ifdef __ASSEMBLY__
#define PAGE_SIZE   (1 << PAGE_SHIFT)
#else
#define PAGE_SIZE   (1UL << PAGE_SHIFT)
#endif
#define PAGE_MASK   (~(PAGE_SIZE-1))
Run Code Online (Sandbox Code Playgroud)

换挡如何给你 4096?

当您移位时,您执行的是 2 的二进制乘法。因此,向左移位 ( 1 << PAGE_SHIFT) 实际上是在执行 2^12 = 4096 的乘法。

$ echo "2^12" | bc
4096
Run Code Online (Sandbox Code Playgroud)

  • @ReverseFlow 为了得到这样的答案,我会问一个单独的问题。 (3认同)
  • 现代硬件支持 2MB 和一些 1GB 的页面大小。可以将 2MB 页面的“PAGE_SHIFT”设置为 21 作为内核构建的默认值吗? (2认同)

Gil*_*il' 21

硬件(特别是MMU,它是 CPU 的一部分)决定了可能的页面大小。与处理器寄存器大小没有关系,与地址空间大小只有间接关系(因为 MMU 决定两者)。

几乎所有架构都支持 4kB 的页面大小。一些架构支持更大的页面(有些还支持更小的页面),但 4kB 是一个非常普遍的默认值。

Linux 支持两种页面大小:

  • 正常大小的页面,我认为在所有体系结构上默认为 4kB,尽管某些体系结构允许其他值,例如ARM64 上的16kB 或IA64上的 8kB、16kB 或 64kB 。这些对应于 MMU 上最深级别的描述符(Linux 称之为PTE)。
  • 巨大的页面,如果编译在 (CONFIG_HUGETLB_PAGE是必要的,并且CONFIG_HUGETLBFS对于大多数用途也是如此)。这对应于 MMU 描述符的第二深级别(Linux 称之为 PMD)(或者至少通常如此,我不知道这是否适用于所有架构)。

页面大小是内存使用、内存使用和速度之间的折衷。

  • 当页面被部分使用时,更大的页面大小意味着更多的浪费,因此系统会更快地耗尽内存。
  • 更深的 MMU 描述符级别意味着更多的内核内存用于页表。
  • 更深的 MMU 描述符级别意味着更多的时间花在页表遍历上。

对于大多数应用程序而言,较大页面大小的收益很小,而成本却很高。这就是为什么大多数系统只使用正常大小的页面。

您可以使用getconf实用程序或 C 函数查询系统上的(正常)页面大小sysconf

$ getconf PAGE_SIZE
4096
Run Code Online (Sandbox Code Playgroud)

使用大页面需要挂载hugetlbfs文件系统并mmap在那里 ping 文件。