Linux内存管理1(基于6.1内核)---内存描述
一、Linux内存描述
Linux 系统中,内存管理是内核的核心组成部分,涉及如何高效地分配、管理和释放内存资源。Linux 的内存管理体系旨在提供一种既能保证进程隔离和安全,又能在多任务环境中实现高效资源利用的方式。内存管理包括虚拟内存、物理内存、内存映射、交换空间等方面。
虚拟内存使得每个进程都认为它独占了整个内存空间,而实际上物理内存通过页面交换和内存映射技术共享给多个进程。Linux 使用页表来映射虚拟地址到物理地址,并通过页框回收、页面交换等机制进行内存管理。它还采用了多种优化技术,如内存分配器(SLAB、SLUB 等)、内存压缩(zswap、zswap)和 NUMA(非一致性内存访问)优化,以应对不同的硬件架构和负载需求。
主要对Linux的UMA和NUMA进行介绍:
1.1 UMA和NUMA两种模型
共享存储型多处理机有两种模型:
-
均匀存储器存取(Uniform-Memory-Access,简称UMA)模型。
将可用内存以连续方式组织起来。
- 非均匀存储器存取(Nonuniform-Memory-Access,简称NUMA)模型。
1.2 UMA模型
传统的多核运算是使用SMP(Symmetric Multi-Processor )模式:将多个处理器与一个集中的存储器和I/O总线相连。所有处理器只能访问同一个物理存储器,因此SMP系统有时也被称为一致存储器访问(UMA)结构体系,一致性意指无论在什么时候,处理器只能为内存的每个数据保持或共享唯一一个数值。
物理存储器被所有处理机均匀共享。所有处理机对所有存储字具有相同的存取时间,这就是为什么称它为均匀存储器存取的原因。每台处理机可以有私用高速缓存,外围设备也以一定形式共享。
SMP的缺点是可伸缩性有限,因为在存储器和I/O接口达到饱和的时候,增加处理器并不能获得更高的性能,与之相对应的有AMP架构,不同核之间有主从关系,如一个核控制另外一个核的业务,可以理解为多核系统中控制平面和数据平面。
1.3 NUMA模型
NUMA模式是一种分布式存储器访问方式,处理器可以同时访问不同的存储器地址,大幅度提高并行性。 NUMA总是多处理器计算机,系统的哪个CPU都有本地内存, 可支持快速的访问, 各个处理器之前通过总线链接起来, 以支持堆其他CPU的本地内存的访问, 当然访问要比本地内存慢。
NUMA模式下,处理器被划分成多个”节点”(node), 每个节点被分配有的本地存储器空间。 所有节点中的处理器都可以访问全部的系统物理存储器,但是访问本节点内的存储器所需要的时间,比访问某些远程节点内的存储器所花的时间要少得多。
其访问时间随存储字的位置不同而变化。其共享存储器物理上是分布在所有处理机的本地存储器上。所有本地存储器的集合组成了全局地址空间,可被所有的处理机访问。处理机访问本地存储器是比较快的,但访问属于另一台处理机的远程存储器则比较慢,因为通过互连网络会产生附加时延。
NUMA 的主要优点是伸缩性。NUMA 体系结构在设计上已超越了 SMP 体系结构在伸缩性上的限制。通过 SMP,所有的内存访问都传递到相同的共享内存总线。这种方式非常适用于 CPU 数量相对较少的情况,但不适用于具有几十个甚至几百个 CPU 的情况,因为这些 CPU 会相互竞争对共享内存总线的访问。NUMA 通过限制任何一条内存总线上的 CPU 数量并依靠高速互连来连接各个节点,从而缓解了这些瓶颈状况。
1.4 UMA模型和NUMA模型对比
特性 | UMA(统一内存架构) | NUMA(非统一内存架构) |
---|---|---|
内存访问 | 所有处理器的内存访问延迟相同 | 处理器对本地内存的访问延迟低,对远程内存的访问延迟高 |
内存结构 | 所有处理器共享统一的内存池 | 每个处理器拥有自己的本地内存,访问其他处理器的内存是远程访问 |
扩展性 | 对处理器数量的扩展性差 | 对多处理器扩展性好,适合大规模系统 |
适用场景 | 小到中型的多核系统 | 大型对称多处理系统、大规模并行计算系统 |
性能 | 随着处理器数量增加,内存访问竞争可能导致性能瓶颈 | 本地内存访问快,远程内存访问慢,需要优化内存分配 |
复杂度 | 相对简单,易于实现 | 复杂,需要操作系统考虑内存亲和性、调度优化 |
二、NUMA模型中Linux内存
Linux适用于各种不同的体系结构, 而不同体系结构在内存管理方面的差别很大. 因此linux内核需要用一种体系结构无关的方式来表示内存。
Linux内核通过插入一些兼容层, 使得不同体系结构的差异很好的被隐藏起来, 内核对一致和非一致内存访问使用相同的数据结构。
2.1 NUMA模型中linux内存的机构
非一致存储器访问(NUMA)模式下
-
处理器被划分成多个”节点”(node), 每个节点被分配有的本地存储器空间. 所有节点中的处理器都可以访问全部的系统物理存储器,但是访问本节点内的存储器所需要的时间,比访问某些远程节点内的存储器所花的时间要少得多。
-
内存被分割成多个区域(BANK,也叫”簇”),依据簇与处理器的”距离”不同, 访问不同簇的代码也会不同. 比如,可能把内存的一个簇指派给每个处理器,或则某个簇和设备卡很近,很适合DMA,那么就指派给该设备。因此当前的多数系统会把内存系统分割成2块区域,一块是专门给CPU去访问,一块是给外围设备板卡的DMA去访问。
在UMA系统中, 内存就相当于一个只使用一个NUMA节点来管理整个系统的内存. 而内存管理的其他地方则认为他们就是在处理一个(伪)NUMA系统。
2.2 Linux物理内存的组织形式
Linux把物理内存划分为三个层次来管理:
层次 | 描述 |
---|---|
存储节点(Node) | CPU被划分为多个节点(node), 内存则被分簇, 每个CPU对应一个本地物理内存, 即一个CPU-node对应一个内存簇bank,即每个内存簇被认为是一个节点。 |
管理区(Zone) | 每个物理内存节点node被划分为多个内存管理区域, 用于表示不同范围的内存, 内核可以使用不同的映射方式映射物理内存。 |
页面(Page) | 内存被细分为多个页面帧, 页面是最基本的页面分配的单位。 |
1. 页帧(Page Frame)
页帧是物理内存的最小管理单位。每个页帧通常是 4KB 或更大的内存块,具体大小取决于系统的架构和配置。Linux 内核通过页表(Page Table)来管理虚拟内存与物理内存之间的映射关系。每个页帧都有一个唯一的物理地址,并且操作系统会管理这些页帧的分配和释放。
特点:
- 每个物理内存页帧通常是 4KB。
- 页帧是虚拟内存管理的基础,内核负责通过页表将虚拟地址映射到物理页帧。
2. 内存区域(Zone)
Linux 将物理内存划分为多个 内存区域(Zone),每个区域管理不同类型的内存。主要的内存区域有:
- ZONE_DMA:这个区域用于存放设备可以直接访问的内存。对于较早的架构(如 x86 32 位),设备可能只能访问 16MB 范围内的内存,这些内存页属于
ZONE_DMA
。 - ZONE_NORMAL:这是操作系统用来分配常规应用程序内存的区域,大多数用户程序使用的内存都属于此区域。
- ZONE_HIGHMEM:这是为那些高于
ZONE_NORMAL
区域的内存区域而设计的,通常用于物理内存大于 4GB 的系统。高端内存用于存储较少使用的内存数据,比如内核的缓存。
特点:
- ZONE_DMA:主要用于低地址的内存区域,这些内存区域一般用来支持低端设备(如 I/O 显卡等)。
- ZONE_NORMAL:最常用的内存区域,操作系统会优先分配来自这个区域的内存。
- ZONE_HIGHMEM:高端内存区域,在 32 位架构和大内存系统中,通常用于存放内存较少使用的页面。
3. 内存节点(NUMA Node)
在 NUMA(非统一内存访问)架构的系统中,物理内存不仅被划分为多个区域,还被划分为多个 内存节点(NUMA Node)。每个 NUMA 节点包含了一组本地内存,这些内存能被该节点的处理器直接访问,访问延迟相对较低。而其他节点的内存则需要通过远程访问,这会引入较高的延迟。
NUMA 节点使得系统能够更有效地管理和利用多核处理器架构中的内存资源,减少远程内存访问的瓶颈,从而提高大规模系统的性能。
特点:
- NUMA 节点用于多处理器系统中,每个节点有自己的本地内存,处理器对本地内存的访问比对远程内存的访问延迟要低。
- 适用于多处理器、高性能计算和大规模并行计算系统。
- 内核会尽量保证进程和内存亲和性,以优化性能,避免不必要的远程内存访问。
2.3 内存节点node
CPU被划分为多个节点(node), 内存则被分簇, 每个CPU对应一个本地物理内存, 即一个CPU-node对应一个内存簇bank,即每个内存簇被认为是一个节点。
系统的物理内存被划分为几个节点(node), 一个node对应一个内存簇bank,即每个内存簇被认为是一个节点。
在LINUX中引入一个数据结构struct pglist_data
,来描述一个node,定义在arch/sparc/include/asm/mmzone.h。(这个结构被typedef pg_data_t)。
-
对于NUMA系统来讲, 整个系统的内存由一个node_data的pg_data_t指针数组来管理。
-
对于PC这样的UMA系统,使用struct pglist_data contig_page_data ,作为系统唯一的node管理所有的内存区域。(UMA系统中中只有一个node)。
可以使用NODE_DATA(node_id)来查找系统中编号为node_id的结点。
UMA结构下由于只有一个结点, 因此该宏总是返回全局的contig_page_data, 而与参数node_id无关。
extern struct pglist_data *node_data[];
#define NODE_DATA(nid) (node_data[(nid)])
在UMA结构的机器中, 只有一个node结点即contig_page_data, 此时NODE_DATA直接指向了全局的contig_page_data, 而与node的编号nid无关。其中全局唯一的内存node结点contig_page_data
#ifndef CONFIG_NEED_MULTIPLE_NODES
extern struct pglist_data contig_page_data;
#define NODE_DATA(nid) (&contig_page_data)
#define NODE_MEM_MAP(nid) mem_map
else
/* ...... */
#endif
在分配一个页面时, Linux采用节点局部分配的策略, 从最靠近运行中的CPU的节点分配内存, 由于进程往往是在同一个CPU上运行, 因此从当前节点得到的内存很可能被用到。
2.4 物理内存区域zone
因为实际的计算机体系结构有硬件的诸多限制, 这限制了页框可以使用的方式。
-
ISA总线的直接内存存储DMA处理器有一个严格的限制:他们只能对RAM的前16MB进行寻址。
-
在具有大容量RAM的现代32位计算机中, CPU不能直接访问所有的物理地址, 因为线性地址空间太小, 内核不可能直接映射所有物理内存到线性地址空间, 我们会在后面典型架构(x86)上内存区域划分详细讲解x86_32上的内存区域划分。
因此Linux内核对不同区域的内存需要采用不同的管理方式和映射方式。
为了解决这些制约条件,Linux使用了三种区:
1. ZONE_DMA
ZONE_DMA(Direct Memory Access 区域)是为需要直接访问内存的设备保留的内存区域。在早期的硬件架构中,特别是在 x86 32 位架构下,一些设备(例如网卡、显卡、声卡等)只能访问物理地址较低的内存区域,因此需要通过这个专用区域进行内存分配。
- 用途:主要用于低地址内存,供需要直接访问物理内存的设备使用(如 I/O 设备)。
- 特点:在 32 位系统中,设备可能只能访问 16MB 或 64MB 范围内的内存,因此这个区域的内存通常限制在较低的地址范围内。
2. ZONE_NORMAL
ZONE_NORMAL 是操作系统常规的内存区域,绝大多数应用程序和操作系统本身的内核代码都会使用这个区域的内存。这个区域的内存可以被大多数进程和内核动态分配,并且其分配优先级通常较高。
- 用途:这是系统中用于动态内存分配的主要区域,适用于常规的内存分配操作。
- 特点:大部分系统的内存(特别是在 64 位系统上)都属于这个区域。它的访问延迟较低,且通常被优先分配。
3. ZONE_HIGHMEM
ZONE_HIGHMEM 是高端内存区域,通常用于物理内存超过 4GB 的系统,尤其是在 32 位系统中。由于 32 位操作系统的地址空间限制(通常为 4GB),操作系统将部分物理内存划分到高端内存区域,进行特定的内存管理处理。
- 用途:用于存放高地址的物理内存区域。在 32 位系统中,操作系统会将高于 4GB 的内存放置在
ZONE_HIGHMEM
区域,这部分内存一般不直接映射到虚拟地址空间,而是通过页面映射进行管理。 - 特点:在 64 位系统中不再有这样严格的限制,
ZONE_HIGHMEM
主要出现在 32 位系统中。
-
ZONE_DMA : 这个区包含的页用来执行DMA操作。
-
ZONE_NOMAL : 这个区包含的都是能正常映射的页。
-
ZONE_HIGHEM : 这个区包”高端内存”,其中的页能不永久地映射到内核地址空间
管理区(内存区域)类型如下分布
物理内存区域分布(总结):
内存区域 | 适用平台 | 物理内存范围 | 主要用途 |
---|---|---|---|
ZONE_DMA | 主要是 32 位系统 | 较低的内存地址范围,通常为 0 - 16MB 或 0 - 64MB | 支持需要 DMA 操作的设备 |
ZONE_NORMAL | 32 位和 64 位系统 | 系统中的常规内存区域,通常占据大部分物理内存 | 用于常规的内存分配,包含内核和用户进程的内存 |
ZONE_HIGHMEM | 主要是 32 位系统 | 超过 4GB 的内存区域 | 32 位系统中用于管理高于 4GB 的内存区域 |
内存区域分布示意(简化版):
|-------------------------------------------------------|
| ZONE_DMA | ZONE_NORMAL | ZONE_HIGHMEM |
| (低地址) | (中地址) | (高地址,主要用于32位系统)|
|-------------------------------------------------------|
- 在 32 位系统 中,
ZONE_DMA
和ZONE_HIGHMEM
是非常重要的内存管理区域,ZONE_HIGHMEM
主要用于管理 4GB 以上的内存,而ZONE_DMA
用于设备需要直接访问的低内存区域。 - 在 64 位系统 中,内存区域管理更为灵活,
ZONE_DMA
的使用已大幅减少,ZONE_HIGHMEM
在 64 位系统中几乎不存在。
内核在初始化内存管理区时, 首先建立管理区表zone。include/linux/mmzone.h
struct zone {
/* Read-mostly fields */
/* zone watermarks, access with *_wmark_pages(zone) macros */
unsigned long _watermark[NR_WMARK];
unsigned long watermark_boost;
unsigned long nr_reserved_highatomic;
/*
* We don't know if the memory that we're going to allocate will be
* freeable or/and it will be released eventually, so to avoid totally
* wasting several GB of ram we must reserve some of the lower zone
* memory (otherwise we risk to run OOM on the lower zones despite
* there being tons of freeable ram on the higher zones). This array is
* recalculated at runtime if the sysctl_lowmem_reserve_ratio sysctl
* changes.
*/
long lowmem_reserve[MAX_NR_ZONES];
#ifdef CONFIG_NUMA
int node;
#endif
struct pglist_data *zone_pgdat;
struct per_cpu_pages __percpu *per_cpu_pageset;
struct per_cpu_zonestat __percpu *per_cpu_zonestats;
/*
* the high and batch values are copied to individual pagesets for
* faster access
*/
int pageset_high;
int pageset_batch;
#ifndef CONFIG_SPARSEMEM
/*
* Flags for a pageblock_nr_pages block. See pageblock-flags.h.
* In SPARSEMEM, this map is stored in struct mem_section
*/
unsigned long *pageblock_flags;
#endif /* CONFIG_SPARSEMEM */
/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
unsigned long zone_start_pfn;
/*
* spanned_pages is the total pages spanned by the zone, including
* holes, which is calculated as:
* spanned_pages = zone_end_pfn - zone_start_pfn;
*
* present_pages is physical pages existing within the zone, which
* is calculated as:
* present_pages = spanned_pages - absent_pages(pages in holes);
*
* present_early_pages is present pages existing within the zone
* located on memory available since early boot, excluding hotplugged
* memory.
*
* managed_pages is present pages managed by the buddy system, which
* is calculated as (reserved_pages includes pages allocated by the
* bootmem allocator):
* managed_pages = present_pages - reserved_pages;
*
* cma pages is present pages that are assigned for CMA use
* (MIGRATE_CMA).
*
* So present_pages may be used by memory hotplug or memory power
* management logic to figure out unmanaged pages by checking
* (present_pages - managed_pages). And managed_pages should be used
* by page allocator and vm scanner to calculate all kinds of watermarks
* and thresholds.
*
* Locking rules:
*
* zone_start_pfn and spanned_pages are protected by span_seqlock.
* It is a seqlock because it has to be read outside of zone->lock,
* and it is done in the main allocator path. But, it is written
* quite infrequently.
*
* The span_seq lock is declared along with zone->lock because it is
* frequently read in proximity to zone->lock. It's good to
* give them a chance of being in the same cacheline.
*
* Write access to present_pages at runtime should be protected by
* mem_hotplug_begin/done(). Any reader who can't tolerant drift of
* present_pages should use get_online_mems() to get a stable value.
*/
atomic_long_t managed_pages;
unsigned long spanned_pages;
unsigned long present_pages;
#if defined(CONFIG_MEMORY_HOTPLUG)
unsigned long present_early_pages;
#endif
#ifdef CONFIG_CMA
unsigned long cma_pages;
#endif
const char *name;
#ifdef CONFIG_MEMORY_ISOLATION
/*
* Number of isolated pageblock. It is used to solve incorrect
* freepage counting problem due to racy retrieving migratetype
* of pageblock. Protected by zone->lock.
*/
unsigned long nr_isolate_pageblock;
#endif
#ifdef CONFIG_MEMORY_HOTPLUG
/* see spanned/present_pages for more description */
seqlock_t span_seqlock;
#endif
int initialized;
/* Write-intensive fields used from the page allocator */
CACHELINE_PADDING(_pad1_);
/* free areas of different sizes */
struct free_area free_area[NR_PAGE_ORDERS];
#ifdef CONFIG_UNACCEPTED_MEMORY
/* Pages to be accepted. All pages on the list are MAX_ORDER */
struct list_head unaccepted_pages;
#endif
/* zone flags, see below */
unsigned long flags;
/* Primarily protects free_area */
spinlock_t lock;
/* Write-intensive fields used by compaction and vmstats. */
CACHELINE_PADDING(_pad2_);
/*
* When free pages are below this point, additional steps are taken
* when reading the number of free pages to avoid per-cpu counter
* drift allowing watermarks to be breached
*/
unsigned long percpu_drift_mark;
#if defined CONFIG_COMPACTION || defined CONFIG_CMA
/* pfn where compaction free scanner should start */
unsigned long compact_cached_free_pfn;
/* pfn where compaction migration scanner should start */
unsigned long compact_cached_migrate_pfn[ASYNC_AND_SYNC];
unsigned long compact_init_migrate_pfn;
unsigned long compact_init_free_pfn;
#endif
#ifdef CONFIG_COMPACTION
/*
* On compaction failure, 1<<compact_defer_shift compactions
* are skipped before trying again. The number attempted since
* last failure is tracked with compact_considered.
* compact_order_failed is the minimum compaction failed order.
*/
unsigned int compact_considered;
unsigned int compact_defer_shift;
int compact_order_failed;
#endif
#if defined CONFIG_COMPACTION || defined CONFIG_CMA
/* Set to true when the PG_migrate_skip bits should be cleared */
bool compact_blockskip_flush;
#endif
bool contiguous;
CACHELINE_PADDING(_pad3_);
/* Zone statistics */
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
atomic_long_t vm_numa_event[NR_VM_NUMA_EVENT_ITEMS];
} ____cacheline_internodealigned_in_smp;
2.5 内存页page
大多数内核(kernel)的操作只使用ZONE_NORMAL区域,系统内存由很多固定大小的内存块组成的,这样的内存块称作为“页”(PAGE),
ARM 架构支持多种页面大小,其中最常见的包括 4KB 页面、64KB 页面、1MB 页面和 16MB 页面。具体的页面大小取决于 ARM 架构的版本(如 ARMv7 或 ARMv8)、配置的页表层级以及内存管理策略。操作系统和硬件可以根据需求选择合适的页面大小,以优化内存管理和性能。
每个物理的页由一个struct page
的数据结构对象来描述。页的数据结构对象都保存在mem_map
全局数组中,该数组通常被存放在ZONE_NORMAL的首部,或者就在小内存系统中为装入内核映像而预留的区域之后。从载入内核的低地址内存区域的后面内存区域,也就是ZONE_NORMAL开始的地方的内存的页的数据结构对象,都保存在这个全局数组中。
2.6 高端内存
Linux 内核引入了高端内存的概念以支持更多的内存地址空间。
1. 内存区域划分
在 Linux 内核中,物理内存被划分为不同的 zone,主要的内存区域有:
- ZONE_DMA:用于直接内存访问(DMA)。它包含的内存用于设备与内存之间的直接数据传输(通常是低地址内存区域)。对低端硬件的支持依赖于该区域。
- ZONE_NORMAL:这是大部分系统应用程序可直接访问的内存区域,位于物理内存的较低部分。此区域的内存可以直接映射到虚拟地址空间,供内核和用户进程使用。
- ZONE_HIGHMEM:也叫高端内存,是指在 32 位系统中,物理内存的高地址部分。由于 32 位系统的虚拟地址空间限制(通常为 4GB),所以不能直接映射所有物理内存,特别是超过 900MB~1GB 的部分。为了有效利用这些内存,Linux 引入了高端内存。
2. 高端内存(High Memory)的背景
在 32 位架构下,虚拟地址空间通常限制为 4GB,实际可用于内核和用户空间的地址空间比例约为 50%(即约 2GB)。ZONE_NORMAL 区域位于这个地址范围内,能够直接映射到虚拟地址空间。而 ZONE_HIGHMEM 区域的内存,则是超过了 2GB 虚拟地址空间的部分,因此需要通过内核的特殊处理进行访问。
在早期的 Linux 系统中,高端内存(位于 2GB 地址以上的部分)不能直接映射到用户空间,因此必须通过内核的辅助机制来访问。这就引出了 高端内存的访问机制。
3. 高端内存的管理
对于 高端内存(High Memory) 的管理,Linux 采用了分段映射的方式。由于 32 位系统虚拟地址空间有限,不能将所有物理内存直接映射到内核虚拟地址空间,Linux 内核需要通过如下机制来处理高端内存:
a. 通过 Page Tables(页表)映射
高端内存通常无法直接映射到内核的虚拟地址空间中。为了能够访问这些内存,内核会在需要时通过 页表映射(page table mapping) 的方式来将高端内存中的一部分映射到内核的虚拟地址空间。这样,内核在访问高端内存时,会进行映射和反映射的操作。
b. 通过内存池(Memory Pools)管理
Linux 为了提高效率,会将内存分成不同的池(如 slab 分配器),并根据不同的内存区域进行动态管理。高端内存的访问通常使用 kmap() 和 kunmap() 函数来映射和取消映射。
- kmap():在需要访问高端内存时,内核使用 kmap() 函数将高端内存页映射到内核的虚拟地址空间中。
- kunmap():访问完成后,内核使用 kunmap() 函数取消高端内存页的映射。
c. 内存区域转换
高端内存通常被分为多个 pages(页)。当需要访问高端内存时,内核会通过 page fault 机制进行映射,将特定的物理内存页映射到内核虚拟地址空间的临时位置。每次访问完毕后,会将映射解除,以释放资源。
4. 高端内存访问的优化
高端内存的访问相对较为复杂,尤其是在 32 位系统中,这种内存管理方式对性能有一定影响。为了解决这一问题,Linux 在高端内存的管理上做了许多优化:
- 高端内存的分段映射:通过分段映射的方式,减少了需要映射的内存页数量,从而提升了性能。
- 使用透明页(Transparent Huge Pages,THP):在某些场景下,可以使用透明大页来管理内存,这对于减少页表的查找开销和提高内存带宽非常有效。
- NUMA 优化:在多处理器(NUMA)系统中,Linux 会根据每个 CPU 节点的内存布局,优化内存的访问方式,减少跨节点的内存访问延迟,进一步提升对高端内存的访问效率。
5. 高端内存与 64 位系统
在 64 位系统中,虚拟地址空间远远大于 32 位系统,因此没有 32 位系统中所面临的虚拟地址空间限制。所有的物理内存,包括高端内存,都可以被直接映射到内核的虚拟地址空间中。因此,64 位系统中的 ZONE_HIGHMEM 区域变得不再需要,内核能够直接访问整个物理内存。
6. 32 位与 64 位系统的区别
- 32 位系统:由于虚拟地址空间有限(通常为 4GB),需要使用 高端内存 的映射机制来管理大于 2GB 的内存部分。
- 64 位系统:虚拟地址空间极其庞大(通常为 16EB),所以没有像 32 位系统那样的内存地址限制,ZONE_HIGHMEM 区域不再存在,内核可以直接访问所有物理内存。