物理内存组织结构

本文介绍了Linux内核中的内存管理,包括UMA(一致内存访问)和NUMA(非一致内存访问)两种体系结构。UMA中,内存以连续方式组织,所有CPU访问速度相同;而在NUMA中,每个CPU有本地内存,访问更快。内存管理还涉及内存模型(平坦、不连续、稀疏)和三级结构(内存节点、内存域、页帧)。此外,文章讨论了内存区域类型(如DMA、DMA32、正常、高端内存)以及页帧作为内存最小单位的角色。
摘要由CSDN通过智能技术生成

内存管理在内核中占据着举足轻重的地位,毕竟它是用来处理处理器和内存之间的协作的,而后两者都是计算机中最为重要的资源。内存管理的目标就是高效合理的使用物理内存,不造成浪费。

1. 体系结构

 

在计算机发展初期,如上图,CPU通过总线访问整个地址空间,这是一种简单经济的方式,可以尽可能使用内存。但是这个系统本身也存在伸缩性的问题,因为总线的宽度是有限的,这也限制了处理器的数量。如果添加CPU,会引起以下两个问题

  • CPU增加,每个节点的可用带宽会减少
  • CPU增加,总线长度会增加,进而增加了延迟

于是有了下面的系统,如下图,其中北桥芯片离CPU最近,在CPU与显卡(PCIE/AGP)、内存(DRAM)等建立通信接口,处理高速信号。南桥则负责一些I/O设备,通常速度相对前者不高。比如PCI、磁盘(IDE/SATA)、USB等。

 

目前管理物理内存的方法主要有以下两种

1.1 一致内存访问(Uniform Memory Access,UMA)

也称为对称多处理器(SMP)  内存以连续的方式组织起来,每个CPU访问各个内存区都一样快。CPU通过系统总线(前端总线)连到北桥(其中包含内存控制器),与内存之间的通信必然经过北桥。IO控制器也连到北桥,IO必须通过北桥才能到达CPU。可以增加多个总线或者内存通道增加带宽。不过总的来将,UMA的这种伸缩性是有限的。

 

 1.2  非一致内存访问(Non-Unit Memory Access,NUMA)

每个CPU是平等的(系统启动初始化除外),都有本地内存,离着最近访问速度最快。各个CPU之间通过总线连接,支持对其他CPU的访问。如下图,CPU不再共享北桥,而是独有一个内存控制器。

 

 

2. 内存模型

从处理器的角度看物理内存分布,内存管理子系统支持下面三种内存模型

  • 平坦内存(Flat Memory):内存的物理地址空间连续,不存在空洞。如果物理地址空间不连续,那要额外的分配页来处理这些空洞,显然这种情况下是低效的。
  • 不连续内存(Discontiguous Memory):如果物理地址空间存在空洞,相对平坦内存能高效处理
  • 稀疏内存(Space Memory):物理地址空间存在空洞,并且支持热拔插。

     

 

3. 三级结构

在NUMA,CPU被划分为多个节点(node), 每个CPU对应一个本地物理内存, 即一个CPU-node对应一个内存node。 内存管理系统通过节点(node),内存域(zone)、页帧(page)三级结构描述物理内存。首先,内存划分为节点,每个节点关联一个CPU。各个节点又划分为内存域,各个内存域都关联了一个数组,用来组织属于该内存域的物理页。UMA被当作只有一个NUMA的系统。

3.1 内存节点

各个内存节点保存在一个单链表中,供内核遍历。

typedef struct pglist_data {
    struct zone node_zones[MAX_NR_ZONES];           //内存区域数组,MAX_NR_ZONES一般为3
    struct zonelist node_zonelists[MAX_ZONELISTS];  //备用区域列表
    int nr_zones;                                   //内存区域数量
#ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */
    struct page *node_mem_map;                      // 页描述符,用于描述节点的所有物理内存页
#ifdef CONFIG_PAGE_EXTENSION
    struct page_ext *node_page_ext;                 //页扩展属性
#endif
#endif
......
    unsigned long node_start_pfn;       //该节点的起始物理页号,系统中所有节点的额页帧是一次编号,全局唯一的。
    unsigned long node_present_pages;   //物理页总数
    unsigned long node_spanned_pages;   //物理页总数包含空洞
    int node_id;                        //节点id
......
} pg_data_t;

3.2 内存域

3.2.1 内存区域类型

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区域。
  • ZONE_DMA32,64位系统,纪要支持直接访问16MB以下的内存设备,又要支持直接访问4GB以下内存的32位设备,需要使用此区域
  • ZONE_NORMAL,普通区域,直接映射到内核虚拟地址空间的内存区域,也称线性映射区域
  • ZONE_HIGHMEM, 高端内存区域,32位系统的产物,内核地址空间只有1GB,于是就分出了低端内存区域+高端内存区域,高端内存区域通过动态映射用来扩展内存。
  • ZONE_MOVABLE,可移动区域,用来避免内存碎片
  • ZONE_DEVICE,设备区域,为了支持持久内存热拔插而增加的内存区域

3.2.2 数据结构

struct zone {
    // 页分配器使用的字段
    unsigned long watermark[NR_WMARK];    // 页分配器使用的水线
    unsigned long nr_reserved_highatomic; 
    long lowmem_reserve[MAX_NR_ZONES];// 当前保留多少页(这些页不能借给高端地址的区域类型)
#ifdef CONFIG_NUMA
    int node;
#endif
    struct pglist_data  *zone_pgdat;        // 指向内存节点的pglist_data实例
    struct per_cpu_pageset __percpu *pageset;
#ifndef CONFIG_SPARSEMEM
    unsigned long       *pageblock_flags;
#endif /* CONFIG_SPARSEMEM */
#ifdef CONFIG_NUMA
    unsigned long       min_unmapped_pages;
    unsigned long       min_slab_pages;
#endif /* CONFIG_NUMA */
    /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
    // 支持不连续内存模型的字段
    unsigned long       zone_start_pfn; // 当前区域的起始页号
    unsigned long       managed_pages;  // 伙伴分配器管理的物理页的数量
    unsigned long       spanned_pages;  // 当前区域总页数,包括空洞
    unsigned long       present_pages;
    const char      *name;
    struct free_area    free_area[MAX_ORDER];
    ......
} ____cacheline_internodealigned_in_smp;

 

3.3 页帧(物理页)

页帧是系统内存中的最小单位,每个页都会对应有一个struct page的实例。一般位4KB。对应内核结构是struct page,里面有很多联合体,这样写的原因是为了节省内存。

参考:

[0] https://frankdenneman.nl/2016/07/07/numa-deep-dive-part-1-uma-numa/

[1] http://www.pcpop.com/article/628956_all.shtml

[2] 深入Linux内核架构

[3] https://ke.qq.com/webcourse/3294666/103425320

[4] https://cloud.tencent.com/developer/article/1366011

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值