前言
本章篇幅过长,拆分几篇博文简述个人对Linux内核内存管理的理解。本博主要描述物理内存在系统的组织模型。
概述
我们或许已经知道,操作系统中的每个进程都分配有虚拟内存空间(虚拟地址空间),此虚拟内存空间由内核负责划分与运维,虚拟地址空间与物理内存间通过页表映射。Linux X86内核架构下通常是4G的虚拟地址空间,按照3:1进行划分,底部3G用于进程用户态,顶部1G用于内核态,而内核只有一个,所以每个进程虚拟地址空间顶部的内容是一样的。
根据物理内存管理方式的不同,可将计算机分为:
UMA计算机:uniform memory access,一致内存访问;
NUMA计算几:non-uniform memory access,非一致内存访问
两者的区别如下:
即:UMA系统将所有内存以连续方式组织供CPU访问,而NUMA系统的每个CPU均有其本地内存,CPU访问本地内存的速度块,而访问非本地内存慢;
(N)UMA模型的内存组织
概述
无论是UMA还是NUMA模型,内核均使用相同的逻辑处理,只不过将UMA模式视作只有一个节点的NUMA。首先,内核将物理内存划分为节点(比如:大型服务器可能有多个内存条/CPU,每个CPU关联几个本地的内存条),用pg_data_t表示;
其次,各个节点又划分成域zone,通过枚举zone_type区分。如普通域、高端内存域、DMA(Direct Memory Access,直接内存存储 )域。
最后,不同的内存域划分成多个页(page),也叫页帧。
DMA域:供特殊的设备访问;
NORMAL域:可直接映射到内核段(虚拟地址)的普通内存域;
HIGMEM域:超出内核段的物理内存区域;
enum zone_type {
#ifdef CONFIG_ZONE_DMA
/*
* ZONE_DMA is used when there are devices that are not able
* to do DMA to all of addressable memory (ZONE_NORMAL). Then we
* carve out the portion of memory that is needed for these devices.
* The range is arch specific.
*
* Some examples
*
* Architecture Limit
* ---------------------------
* parisc, ia64, sparc <4G
* s390 <2G
* arm Various
* alpha Unlimited or 0-16MB.
*
* i386, x86_64 and multiple other arches
* <16M.
*/
ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
/*
* x86_64 needs two ZONE_DMAs because it supports devices that are
* only able to do DMA to the lower 16M but also 32 bit devices that
* can only do DMA areas below 4G.
*/
ZONE_DMA32,
#endif
/*
* Normal addressable memory is in ZONE_NORMAL. DMA operations can be
* performed on pages in ZONE_NORMAL if the DMA devices support
* transfers to all addressable memory.
*/
ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
/*
* A memory area that is only addressable by the kernel through
* mapping portions into its own address space. This is for example
* used by i386 to allow the kernel to address the memory beyond
* 900MB. The kernel will set up special mappings (page
* table entries on i386) for each page that the kernel needs to
* access.
*/
ZONE_HIGHMEM,
#endif
ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
ZONE_DEVICE,
#endif
__MAX_NR_ZONES
};
数据结构
- 内存节点
内核使用pg_data_t结构管理所有内存节点,其自身指针成员pgdat_next(4.4.20内核源码中没有了,改为其他方式)相互串联,形成系统中所有内存节点的节点链。节点结构中又包含域数组:
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES];
…
}pg_data_t;
- 内存域
内核使用zone结构表示内存域,可以想象,域结构中就包含各种页帧的管理成员,如页换出“水印”、冷热页标签等;
struct zone {
unsigned long watermark[NR_WMARK]; /* 水印数组 */
long lowmem_reserve[MAX_NR_ZONES]; /* 保留内存区域,用于内核关键步骤 */
struct per_cpu_pageset __percpu *pageset; /* 冷热页帧列表 */
- 页帧
页帧是物理内存分配的最小单位,由struct page表示。由于每个页帧都对应一个内核结构,因此需保证此结构本身sizeof不能太大,内核使用union结构技巧性的实现这点-----很复杂,此处从略。Linux下查看页帧大小(4K):
zglinux zhaogang # getconf PAGE_SIZE
4096
有了上面的分析,可以用下图总结Linux内核对物理内存表示如下。节点----域----页帧 三级模型。
在内核的内存反碎片化和回收技术中,进一步将页帧区分为:不可移动页、可回收页、可移动页等。使用枚举定义如下:
enum {
MIGRATE_UNMOVABLE,
MIGRATE_MOVABLE,
MIGRATE_RECLAIMABLE,
MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
MIGRATE_CMA,
#endif
#ifdef CONFIG_MEMORY_ISOLATION
MIGRATE_ISOLATE, /* can't allocate from here */
#endif
MIGRATE_TYPES
};
可以通过查看proc文件系统的pagetypeinfo文件查看各阶伙伴系统(用于内核物理页帧的管理)页类型信息:
小结
内核的MM(memory management)模块可谓相当复杂,看了N遍也只感觉是蜻蜓点水,涉及物理内存管理、虚拟内存管理、物理地址--虚拟地址映射(页表)、初始化内存管理等等。本文只是初步讲述关于Linux内存模型组织,希望读者能自行深入分析。