
Linux内核划分内存区域主要是由于历史遗留问题和硬件架构的限制:
- DMA区域 (ZONE_DMA)
为什么存在:
· 早期ISA总线设备只能访问前16MB物理内存(24位地址总线限制)
· 某些老式DMA控制器只能访问前64KB或前16MB内存
· 确保这些老设备能够正常工作
用途:
· 分配给需要DMA操作的老式设备(声卡、网卡等)
· 防止这些设备因为无法访问内存而失败
- 常规区域 (ZONE_NORMAL)
为什么存在:
· 在32位系统中,内核虚拟地址空间有限(通常1GB)
· 这1GB空间需要直接映射到物理内存,称为线性映射或直接映射
· 这个直接映射区域就是ZONE_NORMAL
关键限制:
· 32位系统:内核空间1GB → 直接映射最大896MB
· 这896MB就是ZONE_NORMAL的大小
· 内核可以直接访问这个区域的物理内存,无需特殊映射
- 高端内存区域 (ZONE_HIGHMEM) - 32位系统的特殊产物
核心问题:
32位系统4GB虚拟地址空间分配:
0-3GB:用户空间(每个进程独立)
3-4GB:内核空间(所有进程共享)
内核只有1GB虚拟地址空间,但物理内存可能超过1GB(如2GB、4GB)。
解决方案:
· ZONE_NORMAL(≤896MB):永久映射到内核虚拟地址空间
· ZONE_HIGHMEM(>896MB):动态映射到内核虚拟地址空间
高端内存访问机制:
c
// 临时映射高端内存页面
void *kmap(struct page *page);
void kunmap(struct page *page);
// 原子映射(中断上下文可用)
void *kmap_atomic(struct page *page);
- 64位系统的变化
在64位系统中,情况完全不同:
关键优势:
· 虚拟地址空间极其巨大(x86_64:128TB内核空间)
· 内核可以将所有物理内存直接线性映射
· ZONE_HIGHMEM 不再需要(64位Linux中已移除)
现代64位系统的典型区域:
c
// x86_64架构
ZONE_DMA : 0-16MB // 兼容老设备
ZONE_DMA32 : 16MB-4GB // 32位DMA设备
ZONE_NORMAL : 4GB-64TB // 大部分内存都在这里
// 注意:没有ZONE_HIGHMEM!
- 各区域的物理位置
在32位系统(4GB物理内存)中:
物理地址空间:
0-16MB : ZONE_DMA (DMA区域)
16-896MB : ZONE_NORMAL (常规区域)
896MB-4GB : ZONE_HIGHMEM (高端内存)
↑
└── 超过896MB的部分需要特殊映射
- 内存分配的优先级
内核分配内存时按顺序尝试:
- 先尝试在指定的ZONE分配
- 如果失败,按照fallback顺序尝试其他ZONE
- 例如:ZONE_HIGHMEM → ZONE_NORMAL → ZONE_DMA
总结表格
区域 32位系统 64位系统 主要用途
ZONE_DMA 0-16MB 0-16MB 老式DMA设备
ZONE_NORMAL 16-896MB 4GB以上 内核直接访问的内存
ZONE_HIGHMEM 896MB以上 不存在 动态映射的大内存(32位专用)
ZONE_DMA32 通常无 16MB-4GB 32位DMA设备
为什么保留这种设计?
- 向后兼容:支持老硬件和32位系统
- 性能优化:直接映射区域访问更快
- 资源管理:确保特殊设备有可用内存
- 简化移植:统一的接口,底层实现不同
关键启示:ZONE_HIGHMEM主要是32位时代的临时解决方案,64位系统已基本解决这个问题。但DMA区域仍然保留,确保老设备的兼容性。