内存管理
如果物理内存是分布式的,由多个cell组成(比如每个核有自己的本地内存),那么CPU在访问靠近它的本地内存的时候就比较快,访问其他CPU的内存或者全局内存的时候就比较慢,这种体系结构被称为Non-Uniform Memory Access(NUMA)。
以上是硬件层面上的NUMA,而作为软件层面的Linux,则对NUMA的概念进行了抽象。即便硬件上是一整块连续内存的UMA,Linux也可将其划分为若干的node。同样,即便硬件上是物理内存不连续的NUMA,Linux也可将其视作UMA。
在NUMA系统中,当Linux内核收到内存分配的请求时,它会优先从发出请求的CPU本地或邻近的内存node中寻找空闲内存,这种方式被称作local allocation,local allocation能让接下来的内存访问相对底层的物理资源是local的。
每个node由一个或多个zone组成(我们可能经常在各种对虚拟内存和物理内存的描述中迷失,但以后你见到zone,就知道指的是物理内存),每个zone又由若干page frames组成(一般page frame都是指物理页面)。
因为硬件的限制,内核不能对所有的page frames采用同样的处理方法,因此它将属性相同的page frames归到一个zone中。对zone的划分与硬件相关,对不同的处理器架构是可能不一样的。
pg_data_t
在UMA系统上只有一个pg_data_t,但在NUMA系统上却又多个pg_data_t。
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES];
struct zonelist node_zonelists[MAX_ZONELISTS];
int nr_zones;
#ifdef CONFIG_FLAT_NODE_MEM_MAP
struct page *node_mem_map;
#endif
struct bootmem_data *bdata;
#ifdef CONFIG_MEMORY_HOTPLUG
spinlock_t node_size_lock;
#endif
unsigned long node_start_pfn;
unsigned long node_present_pages;
unsigned long node_spanned_pages;
int node_id;
wait_queue_head_t kswapd_wait;
struct task_struct *kswapd;
int kswapd_max_order;
} pg_data_t;
- node_zones : 是一个数组,包含了结点中各内存域的数据结构
- node_zonelists :指点了备用结点及其内存域的列表,以便在当前结点没有可用空间时,在备用结点分配内存
- nr_zones : 保存结点中不同内存域的数目
- node_mem_map : 指向page实例数组的指针,用于描述结点的所有物理内存页,它包含了结点中所有内存域的页。
- bdata : 用在内核初始化阶段
- node_start_pfn : 该NUMA结点第一个页帧的逻辑编号。系统中所有的页帧是依次编号的,每个页帧的号码都是全局唯一的(不只是结点内唯一)。
- node_present_pages : 结点中页帧的数目
- node_spanned_pages : 该结点以页帧为单位计算的长度,包含内存空洞。
- node_id : 全局结点ID,系统中的NUMA结点都从0开始编号
- kswapd_wait : 交换守护进程的等待队列,在将页帧换出结点时会用到。
- kswapd : 指向负责该结点的交换守护进程的task_struct。
- kswapd_max_order : 定义需要释放的区域的长度。
zone
Zone虽然是用于管理物理内存的,但zone与zone之间并没有任何的物理分割,它只是Linux为了便于管理进行的一种逻辑意义上的划分。Zone在Linux中用struct zone表示:
struct zone {
spinlock_t lock;
unsigned long spanned_pages;
unsigned long present_pages;
unsigned long nr_reserved_highatomic;
atomic_long_t managed_pages;
struct free_area free_area[MAX_ORDER];
unsigned long _watermark[NR_WMARK];
long lowmem_reserve[MA