Linux深入理解内存管理16(基于Linux6.6)---ARM内存空间分配介绍
一、概述
1.1、ARM 内存空间概述
ARM 架构下的内存空间划分与 x86 等其他架构相比存在一些区别。通常情况下,ARM 系统将内存划分为多个区域,每个区域都有不同的作用和访问方式。在 ARM 中,主要的内存区域包括以下几种:
-
用户空间(User Space)
这部分内存由用户进程访问,包括应用程序运行时使用的所有内存。用户空间的大小取决于系统的架构和内核的配置。通常,用户空间的虚拟地址从 0 开始。 -
内核空间(Kernel Space)
内核空间由操作系统内核使用,用于执行操作系统内核、设备驱动、内存管理、系统调用等。内核空间通常从高地址开始,具体范围根据内核配置和 ARM 架构的版本而有所不同。 -
设备内存(Device Memory)
设备内存包含与硬件设备相关的内存区域,包括设备寄存器、DMA(直接内存访问)区域等。设备内存通常映射到内核的虚拟地址空间,以便内核可以直接访问。 -
物理内存(Physical Memory)
物理内存是实际安装在系统中的 RAM。它直接受到硬件的控制,并由内核进行管理。物理内存的管理是内存管理单元(MMU)的职责,MMU 将物理内存映射到虚拟地址空间。
1.2、ARM 架构的内存管理
ARM 架构的内存管理机制通常与 内存管理单元(MMU) 紧密结合,MMU 是 CPU 的一部分,用于将虚拟地址转换为物理地址,并实现内存保护、缓存一致性等功能。ARM 系统的内存管理与 x86 相似,但其内存管理的实现方式和配置方法具有一些特殊性。
1. 虚拟地址与物理地址映射
在 ARM 中,内存地址分为 虚拟地址 和 物理地址 两种。虚拟地址由操作系统中的进程使用,而物理地址则指向实际的内存位置。通过 页表(Page Table),MMU 将虚拟地址映射到物理地址。ARM 使用 四级页表(对于 ARMv7 或更高版本)来管理虚拟地址到物理地址的映射。
- 页表:ARM 内核通过页表映射虚拟地址到物理地址。页表结构可以支持多级分页,从而提高地址映射的效率。
- 页表项:每个页表项包括虚拟地址和物理地址的映射关系,以及是否启用缓存、访问权限等信息。
2. 内存区域的保护与访问权限
ARM 支持通过 MMU 对内存区域进行 保护,包括访问权限、缓存控制等。ARM 使用 页表项的权限位 来控制虚拟地址访问时的权限,例如:
- 可读(Read)
- 可写(Write)
- 可执行(Execute)
这些权限可以用于保护内核空间与用户空间之间的访问隔离、设备内存的访问控制等。
3. 内存管理的关键组成部分
在 ARM 内存管理中,主要涉及以下几个部分:
-
内核的虚拟内存
内核空间的虚拟地址是由内核通过启动时的映射来定义的。通常,内核空间与用户空间的虚拟地址是相互隔离的,内核可以通过页表将内核虚拟地址空间映射到物理内存。 -
内存池(Memory Pools)
ARM 架构下,内核会将内存划分为不同的池。常见的内存池有:- 页池(Page Pool):用于普通内存页的分配。
- 缓冲池(Buffer Pool):用于分配内核的缓冲区,通常用于 I/O 操作。
- DMA 内存池:用于设备的直接内存访问(DMA),通常要求内存区域不被 CPU 缓存。
-
内存分配策略
ARM 的内存分配策略与其他架构相似,但在内存池和访问控制方面有一些独特的实现。内核通过内存分配函数,如kmalloc()
、kfree()
来分配和释放内存。 -
物理内存管理
ARM 系统使用物理内存池来管理物理内存的分配。内存管理的方式有两种:- Buddy 分配算法:这种算法将物理内存分割成大小相同的块,并通过分配和合并来管理内存。
- SLAB 分配器:这种方式主要用于内核对象的内存分配,通过预先分配的内存池来避免频繁的内存分配。
-
设备内存映射
ARM 系统中的设备通常通过内存映射 I/O(MMIO)与 CPU 进行数据交换。设备的内存区域会映射到内核的虚拟地址空间中,通过ioremap()
函数进行动态映射。 -
DMA(直接内存访问)
由于 ARM 广泛应用于嵌入式系统,DMA 在 ARM 系统中使用频繁。DMA 操作允许设备直接读写内存而不通过 CPU,从而提高性能。在进行 DMA 操作时,通常需要使用特殊的内存分配函数,如dma_alloc_coherent()
,以保证设备能够访问的内存是物理连续的。
4. ARM 内存分配与内存映射
ARM 系统在内核空间中通过内存映射的方式来为设备、内核以及用户空间提供地址映射和管理。例如,内核会使用 ioremap()
函数将物理设备内存映射到内核虚拟地址空间,从而使内核能够访问设备的内存和寄存器。
ARM 内核还使用不同的内存分配方案来优化内存的使用和访问:
kmalloc()
:用于常规的内存分配,通常分配小块内存。vmalloc()
:用于分配较大的非连续内存。dma_alloc_coherent()
:用于分配连续的物理内存区域,以支持 DMA 操作。
这些内存分配方法在 ARM 系统中都有其特定的用途和优化。
Linux内核一般将处理器的虚拟地址空间分成两部分,在32系统上,地址空间在用户进程和内核之间划分的典型比例为3:1,在给出的4GB的虚拟地址空间中,0 ~ 3GB将用于用户空间而3GB ~ 4GB将用于内核空间,内核提供了相关的配置项来修改该比例,也就是说Kernel最多寻址1GB的虚拟地址空间。
当CPU启动MMU后,CPU访问的时虚拟地址空间,然后由MMU根据页表转换成物理地址,页表是由Kernel维护的,所以Kernel可以决定1GB的虚拟地址空间具体映射到什么物理地址。但是不管Kernel怎么映射,最多也只能映射1G的物理内存,所以如果一个系统有超过1G的物理内存,在某一时刻,必然有一部分空间是内核无法访问到的,对于该问题内核借助于高端内存(highmem)方法来管理多余的内存。
二、高端内存
对于32系统,内核使用3G ~ 4G的虚拟地址空间,那么只有1G的地址空间可以用来映射物理空间。但是,如果我们使用的内存大于1G的情况,是不是超过1G的内存就无法使用了呢?为此内核引入了一个高端内存的概念,把1G的虚拟地址空间分成两部分
- 低端内存空间:小于high_memory的物理地址空间,这部分的内存物理地址和3G开始的线性地址是一一映射的,也就是说内核使用的线性地址空间3G ~ (3G + high_memory)和物
- 理地址空间0 ~ high_memory一一映射
- 高端内存空间:剩下的128M的线性空间用来映射剩下的大于high_memory的物理地址空间
对于以上,可以知道以下问题
- 对于高端内存high_memory,现在一般是896M,当我们只有512M的内存的时候,就没有高端内存一说了,因为512MB的物理内存已经被kernel直接映射
- 64位系统下不会有high memory,因为64位虚拟地址空间非常大(分给kernel的也很大),完全能够直接映射全部物理内存。
- 在32位系统上,没有任何进程能够有效地使用超过3GB的内存。这意味着购买超过4GB的从理论上是发挥不出其优势
对于iMX6U,由于使用了CMA,所以其高端内存high_memory的地址空间范围为0xe000 0000 ~ 0xFFFF FFFF(512 MB ~ 1024MB)。那么内核如何借助512M高端内存地址空间实现访问访问所有4GB的物理内存。比如当内核项访问高于High_memory的物理地址时,可以从(0xc000 0000 + high_memory) ~ 0xFFFF FFFF地址空间范围内找一段相应大小的空闲虚拟地址,建立映射到想访问的那段物理内存,用完后归还。这样就所有的人都可以借用这段地址空间访问物理地址,访问所有物理内容如下图所示:
可以知道高端内存的最基本思想:借一段地址空间,建立临时地址映射,用完后释放,达到这段地址空间可以循环使用,访问所有物理内存。万一有内核进程或模块一直占用某段逻辑地址空间不释放,怎么办?若真的出现的这种情况,则内核的高端内存地址空间越来越紧张,若都被占用不释放,则没有建立映射到物理内存都无法访问了。
三、Linux内核高端内存的划分
对于高端内存,一般划分如下:
动态内存映射区:虚拟内存中连续,但物理内存不连续的内存,可以在vmalloc区域分配。该机制通常用于用户空间,内核自身会试图尽力避免非连续的物理内存。
永久内存映射区:该区域可访问高端内存,访问方法是使用alloc_page(_GFP_HIGHMEM)分配高端内存页或使用kmap函数将分配到高端内存映射到该区域
固定映射区:固定映射是与物理内存空间中的固定页关联的虚拟地址空间项,该区域和4GB的顶端只有4K的隔离带,其每个地址项都服务于特定的用途。
对于高端内存的划分,其中fixed mapping主要用在boot阶段用来永久性映射一些物理地址固定的数据结构或者硬件地址(比如ACPI表,APIC地址,等等)。kmap area是kernel用来临时建立映射来访问物理页用的,可用的地址空间也比较小。绝大部分reserve了给vmalloc area,vmalloc和ioremap返回的都是这个空间里的地址。
3.1、高端内存的特点
- 内存映射限制:在 32 位系统中,内核空间和用户空间的虚拟地址是有限的。对于物理内存超过低端内存大小的部分,内核需要使用 页表 来动态映射和访问这些内存区域。
- 地址空间划分:在 32 位系统中,内核只能直接映射到虚拟地址空间的一部分。高端内存的物理地址超出了内核直接映射的虚拟地址范围,需要通过 临时映射 或 交换(swap)等方式访问。
- 低端与高端内存的划分依据:不同架构和系统配置下,低端内存和高端内存的大小会有所不同。大多数 Linux 系统使用
Lowmem
(低端内存)和Highmem
(高端内存)来管理内存。具体的划分是由内核根据系统的配置和硬件特性来确定的。
3.2、高端内存的使用和管理
高端内存的管理和使用相较于低端内存复杂一些,Linux 内核使用一些特殊的机制来处理高端内存:
1、Page Highmem
在 32 位系统中,高端内存区域中的内存页不能直接映射到内核虚拟地址空间,因此内核需要通过 临时映射 来访问这些内存页。每个内存页都可能需要通过页表进行访问,这通常涉及到高端页表。
2、高端内存的分配和回收
为了访问高端内存,内核采用了一些特殊的内存分配策略。常见的高端内存分配器包括:
highmem
分配器:用于为高端内存分配页,这些页在使用时需要通过临时映射到内核虚拟地址空间。kmalloc()
和vmalloc()
:这些内存分配函数通常用于低端内存的分配,但它们也可以用于高端内存的分配,只不过在高端内存的情况下,它们需要做额外的工作。
3、内存映射
对于高端内存的访问,内核需要使用 highmem
页映射。内核会临时将这些内存区域映射到内核虚拟地址空间中,以便执行对内存的读写操作。这个映射操作并不持久,只有在需要访问高端内存时才会发生。
4、内存交换(Swap)
高端内存的管理和回收也与内存交换(swap)密切相关。如果高端内存中的页面没有频繁使用,内核可能会将这些页面交换到磁盘上,释放物理内存空间。高端内存页更可能会被交换出去,因为它们不是内核虚拟地址空间的直接一部分。
3.3、高端内存的内核支持
在 Linux 内核中,高端内存通常是通过配置选项进行管理的,特别是对于 32 位系统。内核使用 CONFIG_HIGHMEM
配置选项来启用对高端内存的支持。当高端内存启用时,内核会动态管理这些内存区域,包括在需要时进行临时映射。
1、highmem
的划分
内核通常会将物理内存划分为三类:
- 低端内存(Lowmem):可以直接映射到内核虚拟地址空间。
- 高端内存(Highmem):不能直接映射到内核虚拟地址空间,需要通过临时映射访问。
- 专用内存(Dedicated Memory):通常指设备专用的内存区域,如显存、网络设备的内存等。
2、32 位和 64 位系统的差异
- 32 位系统:在 32 位的 Linux 系统中,内核虚拟地址空间的大小通常较小(例如 3 GB 或 4 GB)。因此,高端内存的使用变得尤为重要。高端内存超出了内核虚拟地址的映射范围,必须通过额外的映射机制来访问这些内存。
- 64 位系统:在 64 位系统中,内核虚拟地址空间大大增加,几乎可以直接映射到系统中所有的物理内存。因此,64 位系统中的高端内存问题较少,很多情况下整个物理内存都可以通过直接映射访问。
四、ARM32内存分布图
了解完低端内存和高端内存的概念,实际上内存布局是怎么样的?Linux内核在启动时,会打印出内核内存空间的布局图,下面是ARM IMX6平台打印出来的内存空间布局图
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
vmalloc : 0xe0800000 - 0xff800000 ( 496 MB)
lowmem : 0xc0000000 - 0xe0000000 ( 512 MB)
pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
.text : 0xc0008000 - 0xc0a00000 (10208 kB)
.init : 0xc0e00000 - 0xc1000000 (2048 kB)
.data : 0xc1000000 - 0xc1074c00 ( 467 kB)
.bss : 0xc1076000 - 0xc10e8eec ( 460 kB)
这部分信息是的打印是在mem_init()函数中实现的
pr_notice("Virtual kernel memory layout:\n"
" vector : 0x%08lx - 0x%08lx (%4ld kB)\n"
#ifdef CONFIG_HAVE_TCM
" DTCM : 0x%08lx - 0x%08lx (%4ld kB)\n"
" ITCM : 0x%08lx - 0x%08lx (%4ld kB)\n"
#endif
" fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
" vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
" lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n"
#ifdef CONFIG_HIGHMEM
" pkmap : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
#ifdef CONFIG_MODULES
" modules : 0x%08lx - 0x%08lx (%4ld MB)\n"
#endif
" .text : 0x%p" " - 0x%p" " (%4td kB)\n"
" .init : 0x%p" " - 0x%p" " (%4td kB)\n"
" .data : 0x%p" " - 0x%p" " (%4td kB)\n"
" .bss : 0x%p" " - 0x%p" " (%4td kB)\n",
MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
(PAGE_SIZE)),
#ifdef CONFIG_HAVE_TCM
MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
MLK(ITCM_OFFSET, (unsigned long) itcm_end),
#endif
MLK(FIXADDR_START, FIXADDR_END),
MLM(VMALLOC_START, VMALLOC_END),
MLM(PAGE_OFFSET, (unsigned long)high_memory),
#ifdef CONFIG_HIGHMEM
MLM(PKMAP_BASE, (PKMAP_BASE) + (LAST_PKMAP) *
(PAGE_SIZE)),
#endif
#ifdef CONFIG_MODULES
MLM(MODULES_VADDR, MODULES_END),
#endif
MLK_ROUNDUP(_text, _etext),
MLK_ROUNDUP(__init_begin, __init_end),
MLK_ROUNDUP(_sdata, _edata),
MLK_ROUNDUP(__bss_start, __bss_stop));
内核image本身占据的内存空间从_text段到 _end段,并且分为如下几段:
- 代码段:_text和 _etext为代码段的起始和结束地址,包含了编译后的内核代码
- init 段:_init_begin 和 _init_end为init段的起始和结束地址,包含了大部分模块初始化的数据
- 数据段:_sdata和 _edata数据段的起始和结束地址,保存大部分内核的变量
- BSS段:bss_start和 _bss_stop为BSS段的开始和结束地址,包含了初始化为0的所有的静态全局变量
那么高端内存的起始地址是如何确定的呢?在内核初始化内存时候,在adjust_lowmem_bounds函数中确定低端内存和高端内存的起始地址。
vmalloc_limit = (u64)(uintptr_t)vmalloc_min - PAGE_OFFSET + PHYS_OFFSET;
arm_lowmem_limit = lowmem_limit;
high_memory = __va(arm_lowmem_limit - 1) + 1;
计算出来内核线性映射512M地址空间,剩下的保留给vmalloc,fixmap和高端向量表使用,内核很多驱动使用vmalloc来分配连续虚拟地址内存,因为有的驱动不需要连续物理地址内存;除此之外,vmalloc还可以用于高端内存的临时映射。对于内核vmalloc空间配置如下
#define VMALLOC_OFFSET (8*1024*1024)
#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
#define VMALLOC_END 0xff800000UL
vmalloc区域在ARM32内核中,从VMALLOC_START开始到VMALLOC_END结束,即从0xe0800000 - 0xff800000,大小为512MB,在VMALLOC_START开始之前有一个8MB的空间,用于捕获越界访问。
4.1、ARM32 架构内存分布图示例
以下是典型的 ARM32 系统内存分布(假设为 32 位的 Linux 系统):
+---------------------------+-----------------------+
| 高端内存 (Highmem) | 内核空间 (Kernel Space) |
| (4GB - 1GB) | (0xC0000000 - 0xFFFFFFFF) |
+---------------------------+-----------------------+
| 低端内存 (Lowmem) | |
| (0GB - 1GB) | |
+---------------------------+-----------------------+
| 用户空间 (User Space) | |
| (0x00000000 - 0xBFFFFFFF) | |
+---------------------------+-----------------------+
4.2、内存区域详细划分
-
用户空间 (User Space)
- 用户空间的虚拟地址范围通常从
0x00000000
到0xBFFFFFFF
,即 0 到 3GB。 - 这是应用程序运行的地方,用户进程运行在这个区域,内存管理和保护机制确保应用程序不能直接访问内核空间。
- 每个进程都有独立的虚拟地址空间,这使得进程间隔离成为可能。
- 用户空间的虚拟地址范围通常从
-
内核空间 (Kernel Space)
- 内核空间通常从
0xC0000000
开始,直到0xFFFFFFFF
,即从 3GB 到 4GB 之间(在 32 位系统上)。 - 内核空间是操作系统内核及其相关数据结构的所在区域,操作系统内核运行在这个区域,具有完全的访问权限。
- 内核空间通常还包括一些硬件映射的内存区域(如外设控制器寄存器、内存映射I/O 等)。
- 在 ARM32 架构中,内核空间和用户空间是严格隔离的,用户程序无法直接访问内核空间。
- 内核空间通常从
-
高端内存 (Highmem)
- 高端内存指的是物理内存中不能直接映射到内核空间的部分,通常存在于 ARM32 系统中的
Lowmem
之上。 - 在内存分配时,高端内存需要通过一些特殊机制(如临时映射、高端内存分配器等)才能被内核使用。
- 对于较老的 ARM32 系统,
Highmem
是内存管理的一个重要概念,尤其是在物理内存大于 1GB 时。ARM32 架构的内存管理在这些高端内存部分需要进行额外的映射和转换。
- 高端内存指的是物理内存中不能直接映射到内核空间的部分,通常存在于 ARM32 系统中的
-
低端内存 (Lowmem)
- 低端内存通常是指可以直接映射到内核虚拟地址空间的内存区域,通常大小为 1GB 以下(
0x00000000
到0x3FFFFFFF
)。 - 低端内存区域由内核直接管理,内核空间中的大多数数据结构、代码等都会被映射到这个区域。
- 在 ARM32 系统中,低端内存对于内核来说是非常重要的,它是内核操作的主要内存区域。
- 低端内存通常是指可以直接映射到内核虚拟地址空间的内存区域,通常大小为 1GB 以下(
4.3、具体的内存区域分布
具体的内存分布可能会根据不同的内核配置、硬件平台、以及是否启用了特定的内存管理选项而有所不同。以下是一个可能的分布示例:
内存分布:
内存区域 | 地址范围 | 大小 | 描述 |
---|---|---|---|
用户空间 (User Space) | 0x00000000 - 0xBFFFFFFF | 3GB | 应用程序和用户进程的地址空间 |
内核空间 (Kernel Space) | 0xC0000000 - 0xFFFFFFFF | 1GB | 操作系统内核的地址空间,包括内核代码和数据 |
高端内存 (Highmem) | 通常从 0x100000000 以上的地址开始 | 根据物理内存大小 | 用于超过 1GB 物理内存的部分,特别在内核内存映射上有限制 |
物理内存 (Physical Memory) | 物理地址范围 | 根据硬件配置 | 系统的实际物理内存,可能大于 4GB |
五、总结
对于高端内存,首先需要明确这是一个物理内存的概念,它仅仅是内核中的内存管理模块看待物理内存的时候的概念。在内核中,除了内存管理模块直接操作物理地址之外,其他的模块,都需要操作虚拟地址,而虚拟地址是需要内存管理模块分配和映射的。例如,有一个2G的内存,现在内核模块如果想要访问物理内存1.5G的地方,应该怎么办呢?
- 首先,不能使用物理地址,你需要使用内存管理模块给你分配虚拟地址,但是虚拟地址0 ~ 3G已经被用户态进程占用去了,作为内核不能使用。
- 其次,对于1.5G的地方就算映射了,也不是你真正要访问的物理内存地址,所以对于内核,能够使用虚拟内存地址,只剩下高端内存这块了。
内核通常把物理内存低于high_memory的地址成为线性映射地址,而高于high_memory以上的成为高端内存。由于32位系统寻址能力只有4GB,对于物理内存高于high_memory而低于4GB的情况,我们就需要从虚拟地址空间中画出一部分来用于动态映射高端内存,这样就可以访问到全部的4GB的内存。而对于映射高端内存的虚拟地址空间,可以划分位固定映射区和临时映射区,后面章节中单独来讲解每个的功能。对于我们现在使用的IMX6U的内核空间的内存分布图如下所示,对于途中的高端内存每个平台可能都不一样,主要是通过客户实际需要来配置。
ARM 架构,尤其是 ARM32 和 ARM64 系统的内存空间分配,会因硬件平台、操作系统、内核配置等因素的不同而有所变化。但总的来说,ARM 系统的内存分配遵循一定的原则和结构,以下是 ARM 架构的内存空间分配的总结:
1. ARM32 架构内存空间分配
在 ARM32 系统中,内存的分配通常划分为 用户空间 和 内核空间。32 位系统最大寻址空间为 4GB,因此内存分布非常重要,通常采用以下的分配方式:
内存分布概述:
区域 | 地址范围 | 大小 | 描述 |
---|---|---|---|
用户空间 | 0x00000000 - 0xBFFFFFFF | 3GB | 应用程序及用户进程的内存地址空间 |
内核空间 | 0xC0000000 - 0xFFFFFFFF | 1GB | 操作系统内核及其相关数据结构的内存区域 |
详细内存划分:
-
用户空间 (User Space):
- 地址范围:从
0x00000000
到0xBFFFFFFF
,即最大 3GB。 - 用途:所有的用户程序(应用程序)都运行在这个区域。每个进程都有独立的虚拟地址空间,不同进程之间互不干扰。
- 特性:用户空间中的进程无法直接访问内核空间,操作系统通过虚拟内存和分页机制来进行隔离。
- 地址范围:从
-
内核空间 (Kernel Space):
- 地址范围:从
0xC0000000
到0xFFFFFFFF
,即最大 1GB。 - 用途:操作系统的内核运行在此区域,包括内核代码、数据结构、驱动程序等。内核拥有对所有硬件资源的控制权限。
- 特性:内核空间具有更高的访问权限,可以直接操作硬件和物理内存。
- 地址范围:从
-
高端内存 (Highmem):
- 描述:通常指的是 1GB 内存之外的部分,且不能直接映射到内核空间的物理内存。内核需要通过临时映射等技术来访问高端内存,主要用于当物理内存超过 1GB 时的情况。
- 用途:ARM32 架构的内存可能存在 "高端内存",特别是在内存较大时,部分内存无法直接映射,需要通过页表转换来访问。
-
低端内存 (Lowmem):
- 描述:通常指的是可以直接映射到内核空间的内存区域,内核能够直接访问此区域的数据。
- 用途:内核和应用程序的堆栈、堆、共享库等部分通常存储在低端内存区域。
2. ARM64 架构内存空间分配
ARM64(ARMv8 及以后)支持更大地址空间,最大支持 64 位虚拟地址,因此内存空间的分配相较于 ARM32 更为宽广。
内存分布概述:
区域 | 地址范围 | 大小 | 描述 |
---|---|---|---|
用户空间 | 0x0000000000000000 - 0x7FFFFFFFFFFFFFFF | 最大 128TB | 用户程序的地址空间。 |
内核空间 | 0x8000000000000000 - 0xFFFFFFFFFFFFFFFF | 最大 128TB | 操作系统内核的地址空间。 |
详细内存划分:
-
用户空间 (User Space):
- 地址范围:通常从
0x0000000000000000
开始,直到0x7FFFFFFFFFFFFFFF
,即最大可用 128TB。 - 用途:用户程序运行在此空间。内存的隔离机制与 ARM32 类似,每个进程拥有独立的地址空间。ARM64 系统支持更大的地址空间和更多的进程。
- 特性:虚拟内存机制和硬件支持保证了用户空间与内核空间的隔离。
- 地址范围:通常从
-
内核空间 (Kernel Space):
- 地址范围:通常从
0x8000000000000000
开始,直到系统支持的最大虚拟地址。 - 用途:操作系统内核、驱动程序、硬件映射等会运行在这个区域。ARM64 架构的内核空间通常会占用较大地址范围,因为其支持更多的内存映射和硬件管理。
- 特性:内核空间具有更高的权限,可以直接访问所有硬件资源。
- 地址范围:通常从
3. 物理内存与虚拟内存
-
虚拟内存:每个程序拥有独立的虚拟地址空间。ARM 系统使用分页(Page Table)机制将虚拟地址映射到物理地址。通过虚拟内存,操作系统可以提供进程隔离、内存保护和共享内存等特性。
-
物理内存:指系统实际安装的内存,ARM 系统根据硬件配置来管理物理内存。虚拟内存的管理通常通过页表来实现物理地址和虚拟地址之间的转换。
-
内存管理单元 (MMU):ARM 处理器中的 MMU 负责虚拟地址到物理地址的转换。MMU 支持多级页表,能够有效地管理不同大小的内存块(如 4KB、2MB 或 1GB 页)。
4. 内存区域特性
-
高端内存 (Highmem):
- ARM32 中,物理内存大于 1GB 的部分可能需要使用高端内存技术。因为内核空间只能直接映射低于 1GB 的内存,高于 1GB 的内存需要通过页表映射。
- ARM64 中,高端内存问题得到显著缓解,因为 64 位系统可以直接映射更大的物理内存。
-
内存映射 I/O (Memory-mapped I/O):
- 在 ARM 系统中,一部分内存区域专门用于映射硬件设备的控制寄存器。这部分内存通常位于内核空间,并且不属于常规内存区域。
5. 内存管理的挑战与优化
- 内存碎片:随着进程的创建和销毁,内存分配可能会产生碎片。内核需要通过内存分配器来管理内存的碎片化问题。
- 页表管理:在 32 位系统中,页表可能会有较大开销,而在 64 位系统中,通过多级页表和硬件支持可以更加高效地管理内存。
- TLB(Translation Lookaside Buffer):TLB 缓存机制用于加速虚拟地址到物理地址的转换,减少页表访问的延迟。