linux内存的管理主要分为两部分,地址管理和存储设备管理。下面针对这两部分介绍一下我对内存管理的理解。 待续...
硬件地址的基本概念
- DRAM域地址:是DRAM控制器所能访问的地址空间集合。
- PCI总线域地址:是PCI设备所能直接访问的地址空间集合。
- 存储器域地址:是CPU所能访问的地址空间集合。
结合下图对上面概念进行解释:

CPU访问DRAM域或PCI总线域地址空间时,都需要进行地址转换(将存储器域地址转换为相应域的地址)。例如:CPU访问DRAM域时,需要进行存储器域地址空间到DRAM域地址空间的转换(由DRAM控制器完成);CPU访问PCI总线域时,需要进行存储器域地址空间到PCI总线域地址空间的转换(由HOST主桥完成)。在x86处理器系统中,会将DRAM域和PCI总线域映射到存储器域空间中,并且其大多数DRAM域中的地址与存储器域中的地址一一对应而且相等,而存储器域的PCI地址与PCI总线域的地址也一一对应而且相等。它们在存储器域空间的映射彼此独立,互不冲突,映射关系由BIOS提供(e820地址映射表)。
PCI设备访问DRAM域地址空间时,首先要经过HOST主桥将PCI总线域地址转换为存储器域地址,然后再由DRAM控制器将存储器域地址转换为DRAM域地址。
待续...
软件地址的基本概念
下面用图对上面概念进行解释:
在X86系统中,所有进程都使用的是逻辑地址,它要通过分段单元硬件电路转换为线性地址,再通过分页单元硬件电路转换为物理地址(即存储器域地址)。
分段单元的逻辑如下图所示(将逻辑地址转换为线性地址)
分页单元的逻辑如下图所示(将线性地址转换为物理地址)
对于X86 CPU中的分段与分页网上有很多资料,我这就不再介绍了。
- 逻辑地址:是一个32位长的地址。所有进程地址都使用逻辑地址。
- 线性地址(也称为虚拟地址):是一个32位长地址,可以用来表示高达4G的地址,值的范围从0x00000000到0xffffffff。它是通过分段单元的硬件电路将逻辑地址转换为线性地址,即将逻辑地址加上一个段起始地址就得到了线性地址。在linux中,所有的段都从0x00000000开始,所以在linux下逻辑地址等于线性地址,即进程地址也是线性地址。后面我们就不再讨论逻辑地址,而都使用线性地址代表进程所使用的地址。
- 物理地址:是通过分页单元的硬件电路将线性地址转换为物理地址。该地址就是上面所说的存储器域地址,是CPU所能访问的地址空间的集合。
下面用图对上面概念进行解释:

在X86系统中,所有进程都使用的是逻辑地址,它要通过分段单元硬件电路转换为线性地址,再通过分页单元硬件电路转换为物理地址(即存储器域地址)。
分段单元的逻辑如下图所示(将逻辑地址转换为线性地址)

分页单元的逻辑如下图所示(将线性地址转换为物理地址)

对于X86 CPU中的分段与分页网上有很多资料,我这就不再介绍了。
前面介绍过,linux内存管理分为地址管理和存储设备管理。存储设备是由page结构进行管理的,每个page结构管理4K内存。地址管理主要是地址映射(线性地址向存储器域地址映射),是由分页单元的逻辑电路完成的。硬件地址映射(存储器域到DRAM域和PCI总线域地址映射)已由BIOS完成,并通过e820存储器域映射表提供给系统使用。
下面看一个包含4G DRAM设备的BIOS-e820图表
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009ec00 (usable)
BIOS-e820: 000000000009ec00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000e0000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 0000000020000000 (usable) (512M)
BIOS-e820: 0000000020000000 - 0000000020200000 (reserved)
BIOS-e820: 0000000020200000 - 0000000040000000 (usable) (512M)
BIOS-e820: 0000000040000000 - 0000000040200000 (reserved)
BIOS-e820: 0000000040200000 - 00000000bad59000 (usable) (2048M)
BIOS-e820: 00000000bad59000 - 00000000bada6000 (ACPI NVS)
BIOS-e820: 00000000bada6000 - 00000000badae000 (ACPI data)
BIOS-e820: 00000000badae000 - 00000000badc1000 (reserved)
BIOS-e820: 00000000badc1000 - 00000000badc2000 (ACPI NVS)
BIOS-e820: 00000000badc2000 - 00000000badd3000 (reserved)
BIOS-e820: 00000000badd3000 - 00000000badd6000 (ACPI NVS)
BIOS-e820: 00000000badd6000 - 00000000badf6000 (reserved)
BIOS-e820: 00000000badf6000 - 00000000badf8000 (usable)
BIOS-e820: 00000000badf8000 - 00000000bae09000 (reserved)
BIOS-e820: 00000000bae09000 - 00000000bae16000 (ACPI NVS)
BIOS-e820: 00000000bae16000 - 00000000bae3b000 (reserved)
BIOS-e820: 00000000bae3b000 - 00000000bae7e000 (ACPI NVS)
BIOS-e820: 00000000bae7e000 - 00000000bb000000 (usable)
BIOS-e820: 00000000bb800000 - 00000000bfa00000 (reserved)
BIOS-e820: 00000000fed1c000 - 00000000fed40000 (reserved)
BIOS-e820: 00000000ff000000 - 0000000100000000 (reserved)
BIOS-e820: 0000000100000000 - 000000013fe00000 (usable) (1024M)
从存储设备管理的角度看,内核根据这个图表获得可用物理内存大小(usable部分),并建立一个page数组(每个page项管理4K内存)对所有可用内存进行管理。同时根据Memory split(用户/内存线性地址空间的分配比例,我的系统是1G/3G user/kernel split)将page数组划分为不同的管理区(DMA、NORMAL、HIGHMEM),并为DMA、NORMAL区的内存建立好页目录/页表的映射关系(管理区的概念后面会介绍)。
从地址管理的角度看,0~3G存储器域地址大部分用于映射DRAM域(也有部分被保留做其它用途,在page数组中对保留区管理的page结构会标识为不可用),3G~4G被用作其它用途,4G~5G存储器域地址被用于映射DRAM域(我们的设备使用了4G DRAM)。我们可以得到以下几点:
待续...
下面看一个包含4G DRAM设备的BIOS-e820图表
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009ec00 (usable)
BIOS-e820: 000000000009ec00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000e0000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 0000000020000000 (usable) (512M)
BIOS-e820: 0000000020000000 - 0000000020200000 (reserved)
BIOS-e820: 0000000020200000 - 0000000040000000 (usable) (512M)
BIOS-e820: 0000000040000000 - 0000000040200000 (reserved)
BIOS-e820: 0000000040200000 - 00000000bad59000 (usable) (2048M)
BIOS-e820: 00000000bad59000 - 00000000bada6000 (ACPI NVS)
BIOS-e820: 00000000bada6000 - 00000000badae000 (ACPI data)
BIOS-e820: 00000000badae000 - 00000000badc1000 (reserved)
BIOS-e820: 00000000badc1000 - 00000000badc2000 (ACPI NVS)
BIOS-e820: 00000000badc2000 - 00000000badd3000 (reserved)
BIOS-e820: 00000000badd3000 - 00000000badd6000 (ACPI NVS)
BIOS-e820: 00000000badd6000 - 00000000badf6000 (reserved)
BIOS-e820: 00000000badf6000 - 00000000badf8000 (usable)
BIOS-e820: 00000000badf8000 - 00000000bae09000 (reserved)
BIOS-e820: 00000000bae09000 - 00000000bae16000 (ACPI NVS)
BIOS-e820: 00000000bae16000 - 00000000bae3b000 (reserved)
BIOS-e820: 00000000bae3b000 - 00000000bae7e000 (ACPI NVS)
BIOS-e820: 00000000bae7e000 - 00000000bb000000 (usable)
BIOS-e820: 00000000bb800000 - 00000000bfa00000 (reserved)
BIOS-e820: 00000000fed1c000 - 00000000fed40000 (reserved)
BIOS-e820: 00000000ff000000 - 0000000100000000 (reserved)
BIOS-e820: 0000000100000000 - 000000013fe00000 (usable) (1024M)
从存储设备管理的角度看,内核根据这个图表获得可用物理内存大小(usable部分),并建立一个page数组(每个page项管理4K内存)对所有可用内存进行管理。同时根据Memory split(用户/内存线性地址空间的分配比例,我的系统是1G/3G user/kernel split)将page数组划分为不同的管理区(DMA、NORMAL、HIGHMEM),并为DMA、NORMAL区的内存建立好页目录/页表的映射关系(管理区的概念后面会介绍)。
从地址管理的角度看,0~3G存储器域地址大部分用于映射DRAM域(也有部分被保留做其它用途,在page数组中对保留区管理的page结构会标识为不可用),3G~4G被用作其它用途,4G~5G存储器域地址被用于映射DRAM域(我们的设备使用了4G DRAM)。我们可以得到以下几点:
- 前3G存储器域地址都被用于映射DRAM域,是为了内核线性地址空间能够多映射一些DRAM空间。因为内核线性地址空间通过页目录/页表映射为存储器域地址,而被映射的这部分存储器域地址映射的DRAM域越多,则意味着内核线性地址空间映射的DRAM空间越多。
- 由于最高1G的DRAM地址被4G~5G的存储器域地址所映射,所以为了能够访问最高1G的DRAM空间,我们必须打开PAE选项,该选项会使CPU的寻址空间增加到36位,即CPU可访问64G存储器域地址。
- 由于我们为内核分配的3G线性地址空间,而这其中还有512M(通过内核启动命令vmalloc=512M设置的)被用于VMALLOC,所以内核只有2.5G线性地址用于映射存储器域地址,也就是说只有2.5G内存被DMA、NORMAL区管理,其余1.5G内存被HIGHMEM区管理(这个区的内存还未进行页目录/页表映射)。
待续...
地址管理
linux将线性地址空间分为user和kernel两个空间
linux内核线性地址空间变量的含义
linux将线性地址空间分为user和kernel两个空间
- USER线性地址空间,指的是可被应用层访问的线性地址空间。其大小(32位处理器) = 4G - KERNEL线性地址空间大小。
- KERNEL线性地址空间,指的是可被内核使用的线性地址空间。其大小 = LOWMEM线性地址空间大小 + VMALLOC线性地址空间大小。
- LOWMEM线性地址空间,它占用了KERNEL线性地址空间中的一部分。其大小 = KERNEL线性地址空间大小 - VMALLOC线性地址空间大小 。
- LOWMEM功能,这段地址空间在启动时已做好地址映射,其映射的物理内存是连续的,并与物理内存地址一一对应。
- VMALLOC线性地址空间,它占用了KERNEL线性地址空间中的另一部分。其大小 = (KERNEL线性地址空间大小 - 物理内存大小) > __VMALLOC_RESERVE ?KERNEL线性地址空间 - 物理内存大小 : __VMALLOC_RESERVE
- VMALLOC功能,用于在内核中分配线性地址连续,但物理地址不需连续的大内存区。这段地址空间初始化时未做任何地址映射。
linux内核线性地址空间变量的含义
- PAGE_OFFSET = __PAGE_OFFSET = CONFIG_PAGE_OFFSET:这个值是用于划分USER线性地址和KERNEL线性地址的分界点。
- __VMALLOC_RESERVE:表示为VMALLOC线性地址空间最小应保留的空间大小,默认是128M。这个值可在系统启动时通过内核参数vmalloc来改变。
- VMALLOC_END:VMALLOC线性地址空间的结束地址。其值 = 最大线性地址 – 其它ROM内存空间大小
- VMALLOC_START:VMALLOC线性地址空间的起始地址。其值 = VMALLOC_END - VMALLOC线性大小(最小为VMALLOC_RESERVE)
- VMALLOC_OFFSET:固定大小为8M,用于再LOWMEM线性地址空间和VMALLOC线性地址空间之间建立一个隔离带,防止它们互相影响。
- MAXMEM:其值为(VMALLOC_END - PAGE_OFFSET - __VMALLOC_RESERVE),表示内核能够直接映射的最大RAM容量,这个值也是相对固定的(与物理内存实际的大小没有关系),因为VMALLOC_END、PAGE_OFFSET、__VMALLOC_RESERVE是相对固定的。
- MAXMEM_PFN:其值为PFN_DOWN(MAXMEM),表示内核能够直接管理的内存页个数。
- MAX_ARCH_PFN:表示CPU最大可访问的内存页数。对应32位CPU,如果其开启了PAE,则MAX_ARCH_PFN=(1ULL<<(36-PAGE_SHIFT))。如果未开启PAE,则MAX_ARCH_PFN=(1ULL<<(32-PAGE_SHIFT))
- max_pfn:是从bios发现的最大的能管理的内存页个数, 与实际内存大小有关,但它的大小不能超过MAX_ARCH_PFN。
当max_pfn <= MAXMEM_PFN时说明实际的物理内存比内核能够线性映射的内存数小,此时就不需要Highmem来管理了。此时就算开启了HIGHMEM,ZONE_HIGHMEM区能够管理的内存大小也是0。
当max_pfn > MAXMEM_PFN时说明实际的物理内存比内核能够线性映射的内存数大,这样多余的那部分物理内存就不能进行线性映射了,必须通过页表映射(即vmalloc来管理), 该物理内存应该由ZONE_HIGHMEM区来管理。而如果没有开启HIGHMEM选项,则这部分内存就丢失了,不再被管理。 - max_low_pfn:低端内存(相对于highmem)的最大页数,这个就是ZONE_NORMAL区能管理的最大页数。
如果实际物理内存比内核能够线性映射的内存数小,max_low_pfn = max_pfn,即所有的内存都归低端内存区管理。
如果实际物理内存比内核能够线性映射的内存数大,max_low_pfn = MAXMEM_PFN,即低端内存区能够管理的最大值就是内核能够线性映射的最大值。 - highmem_pages:高端内存的最大页数,这个是就是ZONE_HIGHMEM区管理的最大页数。其值为(max_fn – max_low_pfn)。
本帖最后由 pywj777 于 2012-05-28 15:52 编辑 存储设备管理(即可使用物理内存空间的管理) linux内核将物理内存空间进行功能区划分(划分时要参考地址管理中线性地址的分配),并通过page结构进行管理
|