内存布局与映射关系

虚拟内存的布局划分与其对应的物理内存之间的映射关系

32位系统

32位系统最大可以访问内存地址范围为0 ~ 4G,这4G内存的被分为用户空间内存内核空间内存

  • 用户空间:0x0000_0000 ~ 0xBFFF_FFFF (0G ~ 3G)
  • 内核空间:0xC000_0000 ~ 0xFFFF_FFFF (3G ~ 4G)

虚拟地址划分

Linux下32位寻址空间的大致分布(虚拟内存):

32bit内存划分

虚拟地址与物理地址之间的关系

32bit内存虚拟地址与物理地址之间的关系

虚拟内存和物理内存的转换通过MMU硬件来实现

32位CPU可以访问的寻址范围只有4G,因此如果物理内存大于4G时,应该如何处理?

目前在linux系统中可以通过PAE可以支持物理内存超过4G的访问,但是此时CPU也必须支持PAE功能,这部分后面有机会研究了详细说明。

在之前一直以为物理内存超过4G与高端内存有关,而实际上高端内存的产生至于虚拟内存地址范围有关,与物理内存无关。

高端内存

High Memory: 解决的问题是在32位CPU下虚拟机地址空间不足带来的问题。

原因:

在内核中我们要进行频繁的虚拟地址(VA)和物理地址(PA)操作,在这种情况下,如何高效的进行VA to PA的转换就很重要。可是如果按照多级页表路径查找,内存访问开销就比较大,因此采用了另一种简单的”fix-mapping”思路,将0xc000 0000~0xffff ffff虚拟地址直接映射到0x0000 0000~0x3fff ffff,也就是将虚拟地址空间最高1G全部映射到物理地址空间最低的1G上,这样VA与PA之间就存在3G的固定偏移,这样PA=VA-3G。

这样使用简单高效,但是也存在局限性,就是在内核空间只能使用1G的物理内存。但是随着技术的发展1G大小的内核空间已经无法满足内核的使用,因此需要将内核空间增大,有人提议重新划分用户空间和内核空间的比例,比如不按照3:1,使用2.5:1.5等,但由于一些特殊场景(比如用户空间使用的内存非常多)会使得用户态运行效率降低,同时带来一些非对其问题,因此也不是一个很好的办法。

最后就引入了高端内存,将内核空间的1G地址,分为两部分,一部分同样采用fix-mapping,另一部分用来dynamic mapping,以X86为例,实际中的做法是,0xC000 0000-0xF7FF FFFF的896MB用作fix-mapping0xF800 0000-0xFFFF FFFF的128MB用作dynamic-mapping,前者仍然对应于物理地址的0x0000 0000-0x37FF FFFF(只不过部分要优先分配给DMA);后者就是所谓的high memory

实际上high memory还被划分为了3个区域,一部分用于vmalloc分配虚拟地址上连续的内存,一部分用于较长期的动态映射(persistent kernel mappings),还有一部分用于编译时可以直接分配物理地址的高端固定映射(fixmaps)
内核空间划分

  • 虚拟内存中连续、但物理内存中不连续的内存区,可以在vmalloc区域分配。该机制通常用于用户过程,内核自身会试图尽力避免非连续的物理地址。内核通常会成功,因为大部分大的内存块都在启动时分配给内核,那时内存的碎片尚不严重。但在已经运行了很长时间的系统上,在内核需要物理内存时,就可能出现可用空间不连续的情况。此类情况,主要出现在动态加载模块时。
  • 持久映射用于将高端内存域中的非持久页映射到内核中
  • 固定映射是与物理地址空间中的固定页关联的虚拟地址空间项,但具体关联的页帧可以自由选择。它与通过固定公式与物理内存关联的直接映射页相反,虚拟固定映射地址与物理内存位置之间的关联可以自行定义,关联建立后内核总是会注意到的。

在linux中高端内存的大小,可以通过启动参数进行指定:

1
2
3
4
highmem=nn[KMG] [KNL,BOOT] forces the highmem zone to have an exact
size of <nn>. This works even on boxes that have no
highmem otherwise. This also works to reduce highmem
size on bigger boxes.

Documentation/admin-guide/kernel-parameters.txt

在64位系统中,不存在这个问题,因此64位系统的内存划分不存在高端内存(High Memory)

PAE

  • linux内存管理之PAE(物理地址扩展)解决内存大于4G的问题

虚拟内存空间与进程地址空间

32bit_RAM_layer_

64位系统

环境:arm64CPU,linux系统

64bit内存地址可用空间为0x0000 0000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF

64位CPU的寻址分三种:

64位寻址区域划分

ARM64架构的处理器采用的是48位的物理寻址方式。用户空间和内核空间最大支持256TB的地址空间。

1
2
config ARM64_PA_BITS_48
bool "48-bit"
  • 内核空间 :0xFFFF 0000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF (256TB)
  • 非规范区 :0x0000 FFFF FFFF FFFF ~ 0xFFFF 0000 0000 0000 (未使用)
  • 用户空间 :0x0000 0000 0000 0000 ~ 0x0000 FFFF FFFF FFFF (256TB)

48位寻址划分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::

Start End Size Use
-----------------------------------------------------------------------
0000000000000000 0000ffffffffffff 256TB user
ffff000000000000 ffff7fffffffffff 128TB kernel logical memory map
ffff800000000000 ffff9fffffffffff 32TB kasan shadow region
ffffa00000000000 ffffa00007ffffff 128MB bpf jit region
ffffa00008000000 ffffa0000fffffff 128MB modules
ffffa00010000000 fffffdffbffeffff ~93TB vmalloc
fffffdffbfff0000 fffffdfffe5f8fff ~998MB [guard region]
fffffdfffe5f9000 fffffdfffe9fffff 4124KB fixed mappings
fffffdfffea00000 fffffdfffebfffff 2MB [guard region]
fffffdfffec00000 fffffdffffbfffff 16MB PCI I/O space
fffffdffffc00000 fffffdffffdfffff 2MB [guard region]
fffffdffffe00000 ffffffffffdfffff 2TB vmemmap
ffffffffffe00000 ffffffffffffffff 2MB [guard region]

48位寻址划分

参考

  • linux的高端内存是什么?
  • Documentation/arm64/memory.rst
  • Documentation/x86/x86_64/mm.rst