欢迎光临散文网 会员登陆 & 注册

一文玩转Linux内核架构的内存管理(NUMA模型中的内存组织)

2022-05-19 13:54 作者:补给站Linux内核  | 我要投稿

一,概述

  • 内存通过节点(pg_data_t)来管理,每个节点关联到系统中的一个处理器节点又进一步划分为内存域,是对内存的进一步细分,一个节点最多有3个内存域。各个内存域关联了一个数组,用来组织属于该内存域的物理内存页(页帧)。对各个页帧,都分配了一个struct page实例以及所需的管理数据。除了节点自己的内存域,每个节点还提供了一个备用列表(struct zonelist),该列表包含了其他节点,可用于代替当前节点分配内存。

二,数据结构

1. 内存域类型

【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)     

  1. node_zones:包含了节点内各内存域的数据结构.

  2. node_zonelists:指定了备用节点及其内存域的列表,如果当前节点没有可用空间时,可在备用节点内分配内存

  3. nr_zones:节点内内存域的个数

  4. node_mem_map:包含节点内的所有物理内存页

  5. bdata:指向自举内存分配器数据结构的实例

  6. node_start_pfn:该节点内第一个页帧的逻辑编号,系统内所有页帧是依次编号的,每个页帧的号码是全局唯一的

  7. node_present_pages:节点中页帧的个数

  8. node_spanned_pages:节点中包含空洞的页帧个数

  9. node_id:全局节点ID

  10. pgdat_next:连接到下一个内存节点,系统中的所有内存节点都通过单链表连接起来.

  11. kswapd_wait:交换守护进程的等待队列.


【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)     


  1. 节点状态管理数据结构

  2. static inline void node_set_state(int node, enum node_states state)

  3. static inline void node_clear_state(int node, enum node_states state)

3.内存域

  1. ZONE_PADDING:生成填充字段,使常用数据结构处于自身的缓冲行中

  2. pages_min, pages_high,pages_low:页换出时使用的内存水印,如果内存不足,内核可以将页写到硬盘

  3. 空闲页多于pages_high:内存域是理想状态

  4. 空闲页低于pages_low:内核开始将页换出到硬盘

  5. 空闲页低于page_min:页回收工作压力大

  6. lowmem_reserve:用于一些无论如何都不能失败的关键性内存分配,分别为各个内存域指定了若干页

  7. pageset:用于实现每个CPU的热/冷页帧列表,用于保存可用于满足分配的新鲜页,仍然在高速缓存中的称为热页

  8. free_area:用于实现伙伴系统,每个数组元素表示固定长度的一些连续内存区

  9. active_list:活动页的集合

  10. inactive_list:不活动页的集合

  11. nr_scan_active和nr_scan_inactive:内存回收时需要扫描的活动和不活动页的数据

  12. pages_scanned:从上次换出一页以来,有多少页未能成功扫描

  13. flags:内存域的当前状态

  1. ZONE_ALL_UNRECLAIMABLE:页无法回收

  2. ZONE_RECLAIM_LOCKED:CPU回收内存域时设置,阻止其他CPU进行同样操作

  3. ZONE_OOM_LOCKED:内核试图杀死消耗进程最多的进程时设置该标志位

  4. vm_stat:维护该内存域的统计信息

  5. prev_priority:上一次扫描该内存域的优先级

  6. wait_table, wait_table_bits和wait_table_hash_nr_entries实现了一个等待队列,可用于等待某一页表变为可用的进程

  7. zone_pgdat:指向父节点

4.内存域水印

  • 在计算内存水印前,内核首先要确定为关键性分配保留的内存空间的最小值,该值随可用内存大小而非线性增长,并保存在全局变量min_free_kbytes中,一个不变的约束是不能少于128k也不能多于64MB。

  • 数据结构中水印值的填充由init_per_zone_pages_min处理,该函数在内核启动期间调用,主要调用如下两个函数:

  • setup_per_zone_pages_min负责设置struct zone中的pages_min,pages_low和pages_high成员,在计算出高端内存区域之外的页面总数后(保存在lowmem_pages),内核迭代系统中的所有内存域并执行相关计算

  • lowmem_reserve的计算由setup_per_zone_lowmem_reserve完成,内核迭代系统中所有节点,对每个节点的各个内存域分别计算预留内存最小值

5. 冷热页

  • struct zone的pageset成员用于实现冷热分配器,热页是指那些加载到CPU高速缓存的页,其数据访问速度比不在高速缓存中的冷页快

  1. cout:该列表相关的页的数目

  2. high:如果count > high则表明列表中的页太多了

  3. list:双链表,保存了当前CPU的冷页或者热页

6. 页帧

  • 页帧是系统内存的最小单位,对内存中的每一个页都会创建struct page的一个实例

  • 页的广泛使用,增加了struct page的复杂性(内核不同部分对相同的数据有不同的解释)和保持结构长度的难度。

  1. slab,freelist和inuse用于slub分配器

  2. flags存储了和体系结构无关的标志,用于描述页的属性

  3. _count是一个使用计数,表示内核中引用该页的次数

  4. _mapcount表示在页表中有多少项指向该页

  5. lru是一个表头,用于在各种链表上维护该页,以便将页按照不同类别分组,最重要的类别是活动和不活动页

  6. 内核可以将多个毗连的页合并为较大的复合页,第一个页称作首页,而所有其余各页叫做尾页,所有尾页对应的page实例,都将first_page设置为指向首页

  7. mapping指定了页帧所在的地址空间,index是页帧在映射内部的偏移量,地址空间是一个非常一般的概念,例如,可以用在向内存读取文件时,用于将文件的内容与装载数据的内存区关联起来。通过一个小技巧,mapping不仅能保存一个指针,还能包含一些额外的信息,用于判断页是否属于某个未关联到地址空间某个匿名内存区:如果将mapping最低位置1,该指针指向另外一个数据结构(anon_vma),这个结构对实现匿名映射的逆向映射很重要

  8. private指向私有数据的指针,根据页的用途,可以用不同方式使用该指针

  9. virtual用于高端内存区域中的页

  10. 体系结构无关的标志

  11. PG_locked:锁定页面不允许内核的其他部分访问.

  12. PG_error:涉及该页的I/O操作期间发生错误.

  13. PG_referenced, PG_active:控制系统中使用该页的活跃程度.

  14. PG_uptodate:页的数据已经从块设备读取,其间没有出错

  15. PG_dirty:与硬盘上的数据相比,页的内容发生改变.

  16. PG_lru:有助于实现页面回收和切换,内核使用两个最近最少使用链表来区分活动页和不活动页,如果页在其中一个链表中,该位置位,如果在活动链表中,PG_active会置位

  17. PG_highmem:页在高端内存中

  18. PG_private:表明page的private成员非空

  19. PG_writeback:页的内容处于向块设备回写过程中

  20. PG_slab:页是slab分配器的一部分

  21. PG_swapcache:页处于交换缓存中

  22. PG_reclaim:内核决定回收特定页时设置

  23. PG_compound:该页属于一个更大复合页

  24. PG_buddy:表明页空闲且包含在伙伴系统的列表中


一文玩转Linux内核架构的内存管理(NUMA模型中的内存组织)的评论 (共 条)

分享到微博请遵守国家法律