32bit架构
可以配置两种不同的划分
1G(内核空间)/3G(用户空间)
- ZONE_DMA 内存开始的16MB
- ZONE_NORMAL 16MB~896MB
- ZONE_HIGHMEM 896MB ~ 结束
DMA&NORMAL是直接映射到3G~3G+896M,其余部分(如0~3G的用户空间,内核空间的后半部分vmalloc等)则是映射到HIGHMEM
4G(内核空间)/4G(用户空间)
- ZONE_DMA 内存开始的16MB
- ZONE_NORMAL 16MB~3968MB
- ZONE_HIGHMEM 3968MB ~ 结束
64bit架构
- ZONE_DMA 内存开始的16MB
- ZONE_DMA32 16MB~4GB
- ZONE_NORMAL 4GB ~ 结束
上述描述用图片来表示:
物理内存起始的特殊区域
可以使用cat /proc/iomem查看
第一个4K是保留给BIOS用的。
中间一段640K原则上是可用的,但一般空着
1M稍微往前一点是只读ROM(比如系统BIOS和显卡ROM)
1M (第二兆起始处)即_text, 内核代码段
_etext到_edata是内核数据段,有大部分内核变量
_edata到_end是初始化数据,内核启动后就不需要了(如初始化为0的静态全局变量BBS段)
上图640K和大于_end的区域被称为动态内存,全部由Buddy管理。
一些注意点
- highmem存在的意义:对32bit来说,如果没有highmem, 那么内核的1G地址空间就无法映射到整个物理地址(即使内核可以使用的内存总量仍然只有1G);对64bit来说,原本的128T内核地址空间已经够大了,已经能够映射到现有的(小于128T)的物理地址了,因此不需要highmem。
- 32bit时,normal里的内存也是可以给用户空间使用的,只要是空闲的
- DMA32: It exists because the transition to large memory 64-bit machines has created a class of hardware that can only do DMA to the low 4 GBytes of memory.
- 例如只有2G物理内存的64bit Linux没有NORMAL
- the special zones (DMA, DMA32, and on 32-bit machines, Normal) will only be present on one node, generally node 0. All other nodes will generally have only Normal (on 64-bit kernels) or HighMem (on 32-bit kernels) memory. 这一点我很赞同,因为我在实验室的几台NUMA机器上都只在node0看到DMA和DMA32,其余node只有NORMAL。(而很多经典的内核书都说每个node都有DMA和NORMAL)
- 每个zone有一个单独的buddy system进行内存分配。
虚拟内存布局(进程内存布局)
32bit架构
用户空间:0~3G
- linux 2.6.7以前
- linux 2.6.7以后
2.6.7以后的布局明显更加合理,因为栈应该是固定大小的,而堆不应该受到内存映射的起始位置的限制。
2.6.7以后的布局使得堆能够充分使用空闲的地址空间。
全局数据区 = data segment + bss segment
data segment:
- 保存已初始化的全局变量
- 在可执行程序中占据大量空间,记录了其初始化的值
- 系统加载时为其加载初始值
bss segment:
- 保存未初始化的全局变量
- 在可执行程序中仅记录符号名和所占空间大小,仅占极少空间
- 系统加载时将其分配到一块已初始化为0的bss数据区
text segment:
- 保存二进制代码
3~4G内核空间
high_memory 经常为896M (1024-128)
vmalloc_offset 经常为8M, 用于防止越界的隔离
2pages 也是防止越界的隔离
此处3:1的比例是可以调整的
64bit架构
低位的128TB是用户空间
高位的128TB是内核空间
用户空间
内核空间