上一章我们梳理了Node
, Zone
, Page Frame
的整个流程,本章就来整理其关系和数据结构之间的关系。
1. 基本概念
NUMA(Non-Uniform Memory Access,非统一内存访问)和UMA(Uniform Memory Access,统一内存访问):
- NUMA是从处理器对内存访问速度不同的结构
- UMA是处理器与所有内存的访问速度相同的结构
结点Node:
- 从1个CPU访问速度相同的内存集合
- 每个CPU对应一个本地物理内存
- 在内核中用pg_data_t类型,表示节点的结构体成为节点描述符
ZONE:
- 节点中具有相同属性的区域
- 内核使用struct zone结构体管理
页帧Page:
- ZONE中管理物理内存的最小单位称为页帧
- 页帧在Linux中由page结构体管理,通过mem_map全局数据访问
Linux采用Node、Zone和页三级结构来描述物理内存的,如图所示
2. 结点
Linux采用一个struct pg_data_t结构体来描述系统的内存,每一个Node都对应一个struct pglist_data,系统中每个节点都挂接在一个pgdat_list列表中,对于NUMA系统中一个,使用的全局变量struct pglist_data __refdata contig_page_data
。
下面就对结构体提的主要域进行说明
结构体成员变量 | 说明 |
---|---|
node_zones | 该结点的zone类型,一般包括ZONE_HIGHMEM、ZONE_NORMAL和ZONE_DMA三类,包含了节点中各个内存域的数据结构 |
node_zonelists | 指定了备用节点及其内存域列表,以便在当前结点没有可用空间时,在备用结点分配内存 |
nr_zones | 该结点的zone个数,可以从1到3,但并不是所有的结点都需要有3个zone |
node_mem_map | 它是structpage数组的第一页,该数组表示结点中的每个物理页框。根据该结点在系统中的顺序,它可在全局mem_map数组中的某个位置 |
node_start_pfn | 当前NUMA节点第一页帧逻辑编号。在UMA总是0. |
node_present_pages | 总共可用的页面数 |
node_spanned_pages | 总共的页面数,包括有空洞的区域 |
kswapd | 页面回收进程 |
3. ZONE
每个结点的内存被分为多个块,称为zones,它表示内存中一段区域。一个zone用struct_zone_t结构描述,zone的类型主要有ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。ZONE_DMA位于低端的内存空间,用于某些旧的ISA设备,ISA总线的直接内存存储DMA,只能对RAM的前16MB进行寻址。ZONE_NORMAL的内存直接映射到Linux内核线性地址空间的高端部分,许多内核操作只能在ZONE_NORMAL中进行。因此对于内核来说, 不同范围的物理内存采用不同的管理方式和映射方式,Linux使用enum zone_type来标记内核所支持的所有内存区域
enum zone_type
{
#ifdef CONFIG_ZONE_DMA
ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
ZONE_DMA32,
#endif
ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
ZONE_HIGHMEM,
#endif
ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
ZONE_DEVICE,
#endif
__MAX_NR_ZONES
}
其定义如下表所示
管理内存域 | 描述 |
---|---|
ZONE_DMA | 标记了适合DMA的内存域.该区域的 长度依赖于处理器类型 .这是由于古老的ISA设备强加的边界.但是为了兼容性,现代的计算机也可能受此影响 |
ZONE_DMA32 | 标记了 使用32位地址字可寻址,适合DMA的内存域 ,在 32位系统中,本区域是空的 ,即长度为0MB,在Alpha和AMD64系统上,该内存的长度可能是从0到4GB |
ZONE_NORMAL | 标记了可 直接映射到内存段的普通内存域 .这是在 所有体系结构上保证会存在的唯一内存区域 |
ZONE_HIGHMEM | 标记了 超出内核虚拟地址空间 的 物理内存段 ,因此这段地址 不能被内核直接映射 |
ZONE_MOVABLE | 内核定义了一个伪内存域ZONE_MOVABLE,在 防止物理内存碎片的机制memorymigration中需要使用 该内存域.供防止 物理内存碎片的极致使用 |
ZONE_DEVIC | 为支持 热插拔设备 而分配的NonVolatileMemory非易失性内存 |
Zone是用struct zone_t描述的,它跟踪页框使用、空闲区域和锁等信息,结构体中主要域说明如下
结构体成员变量 | 说明 |
---|---|
watermark | 水位值,WMARK_MIN/WMARK_LOV/WMARK_HIGH,页面分配器和kswapd页面回收中会用到 |
lowmem_reserve | zone中预留的内存,用于一些无论如何都不能失败的关键性内存分配 |
zone_pgdat | 执行所属的pglist_data |
pageset | Per-CPU上的页面,减少自旋锁的争用 |
zone_start_pfn | ZONE的起始内存页面帧号 |
managed_pages | 被BuddySystem管理的页面数量 |
spanned_pages | ZONE中总共的页面数,包含空洞的区域 |
present_pages | ONE里实际管理的页面数量 |
structfree_areafree_area[MAX_ORDER]; | 管理空闲页面的列表 |
当系统中可用的内存比较少时,kswapd将被唤醒,并进行页交换。如果需要内存的压力非常大,进程将同步释放内存。每个zone有三个阙值,成为pages_low/pages_min/pages_high,用于跟踪该zone的内存压力。
- pages_min的页框数是由内存初始化free_area_init_core函数,根据zone内页框的比例计算,最小为20页,最大一般为255页
- 当到达pages_min时,说明页面数非常紧张,分配页面的动作和kswapd线程同步运行
- 当空闲也的数目达到pages_low时,说明页面刚开始紧张,则kswapd线程将被唤醒,并开始释放回收页面
- 当达到pages_high时,说明内存页面数很充足,不需要回收,kswapd线程将重新休眠,通常这个数值是page_min的3倍
4. page
每个物理页框都需要一个对应的page结构来进行管理,记录分配状态,分配和回收,互斥以及同步存在。 因为内核会为每一个物理页帧创建一个struct page的结构体,因此要保证page结构体足够的小,否则仅struct page就要占用大量的内存。出于节省内存的考虑,struct page中使用了大量的联合体union。
5. 总结
本章梳理了Node
, Zone
, Page Frame
各个数据结构的成员变量和关系,对于Linux中管理内存的各个结构体之间的关系图如下图所示
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。