内存学习(五):物理内存组织

简介: 内存学习(五):物理内存组织

物理内存组织

1 体系结构

目前多处理器系统有两种体系结构。

  • **(1)非一致内存访问(Non-Uniform Memory Access, NUMA):**指内存被划分成多个内存节点的多处理器系统,访问一个内存节点花费的时间取决于处理器和内存节点的距离。每个处理器有一个本地内存节点,处理器访问本地内存节点的速度比访问其他内存节点的速度快。NUMA是中高端服务器的主流体系结构。
  • **(2)对称多处理器(Symmetric Multi-Processor, SMP):**即一致内存访问(Uniform Memory Access, UMA),所有处理器访问内存花费的时间是相同的。每个处理器的地位是平等的,仅在内核初始化的时候不平等:“0号处理器作为引导处理器负责初始化内核,其他处理器等待内核初始化完成。”

在实际应用中可以采用混合体系结构,在NUMA节点内部使用SMP体系结构。

2 内存模型

内存模型是从处理器的角度看到的物理内存分布情况,内核管理不同内存模型的方式存在差异。内存管理子系统支持3种内存模型。

  • (1)平坦内存(Flat Memory):内存的物理地址空间是连续的,没有空洞。
  • (2)不连续内存(Discontiguous Memory):内存的物理地址空间存在空洞,这种模型可以高效地处理空洞。
  • (3)稀疏内存(Sparse Memory):内存的物理地址空间存在空洞。如果要支持内存热插拔,只能选择稀疏内存模型。

什么情况会出现内存的物理地址空间存在空洞

系统包含多块物理内存,两块内存的物理地址空间之间存在空洞。一块内存的物理地址空间也可能存在空洞,可以查看处理器的参考手册获取分配给内存的物理地址空间。

如果内存的物理地址空间是连续的,不连续内存模型会产生额外的开销,降低性能,所以平坦内存模型是更好的选择。如果内存的物理地址空间存在空洞,应该选择哪种内存模型?

平坦内存模型会为空洞分配page结构体,浪费内存;

而不连续内存模型对空洞做了优化处理,不会为空洞分配page结构体。

和平坦内存模型相比,不连续内存模型是更好的选择。

稀疏内存模型是实验性的,尽量不要选择稀疏内存模型,除非内存的物理地址空间很稀疏,或者要支持内存热插拔。其他情况应该选择不连续内存模型。

3 三级结构

内存管理子系统使用节点(node)、区域(zone)和页(page)三级结构描述物理内存。

1.内存节点

内存节点分两种情况。

  • (1)NUMA系统的内存节点,根据处理器和内存的距离划分。
  • (2)在具有不连续内存的UMA系统中,表示比区域的级别更高的内存区域,根据物理地址是否连续划分,每块物理地址连续的内存是一个内存节点。

内存节点使用一个pglist_data结构体描述内存布局。内核定义了宏NODE_DATA(nid),它用来获取节点的pglist_data实例。对于平坦内存模型,只有一个pglist_data实例contig_page_data。

图片

  • 成员node_id是节点标识符。
  • 成员node_zones是内存区域数组
  • 成员nr_zones是内存节点包含的内存区域的数量
  • 成员node_start_pfn是起始物理页号
  • 成员node_present_pages是实际存在的物理页的总数
  • 成员node_spanned_pages是包括空洞的物理页总数
  • 成员node_mem_map指向页描述符数组每个物理页对应一个页描述符。注意:成员node_mem_map可能不是指向数组的第一个元素,因为页描述符数组的大小必须对齐到2的(MAX_ORDER − 1)次方,(MAX_ORDER − 1)是页分配器可分配的最大阶数。

pglist_data结构体的主要成员如下:

include/linux/mmzone.h
    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;                      /* 页描述符数组 */
    #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;                                     /* 节点标识符 */
    } pg_data_t;

2.内存区域

1-内存节点被划分为内存区域

内存节点被划分为内存区域,内核定义的区域类型如下:

include/linux/mmzone.h
    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
    };
  • DMA区域(ZONE_DMA):DMA是“Direct Memory Access”的缩写,意思是直接内存访问。如果有些设备不能直接访问所有内存,需要使用DMA区域。例如旧的工业标准体系结构(Industry Standard Architecture, ISA)总线只能直接访问16MB以下的内存。
  • DMA32区域(ZONE_DMA32):64位系统,如果既要支持只能直接访问16MB以下内存的设备,又要支持只能直接访问4GB以下内存的32位设备,那么必须使用DMA32区域。
  • 普通区域(ZONE_NORMAL):直接映射到内核虚拟地址空间的内存区域,直译为“普通区域”,意译为“直接映射区域”或“线性映射区域”。内核虚拟地址和物理地址是线性映射的关系,即虚拟地址 =(物理地址 + 常量)。是否需要使用页表映射?不同处理器的实现不同,例如ARM处理器需要使用页表映射,而MIPS处理器不需要使用页表映射。
  • 高端内存区域(ZONE_HIGHMEM):这是32位时代的产物,内核和用户地址空间按1 : 3划分,内核地址空间只有1GB,不能把1GB以上的内存直接映射到内核地址空间,把不能直接映射的内存划分到高端内存区域。通常把DMA区域、DMA32区域和普通区域统称为低端内存区域。64位系统的内核虚拟地址空间非常大,不再需要高端内存区域。
  • 可移动区域(ZONE_MOVABLE):它是一个伪内存区域,用来防止内存碎片,后面讲反碎片技术的时候具体描述。
  • 设备区域(ZONE_DEVICE):为支持持久内存(persistent memory)热插拔增加的内存区域。

每个内存区域用一个zone结构体描述,其主要成员如下:

2-zone结构体
include/linux/mmzone.h
    struct zone {
          unsigned long watermark[NR_WMARK];        /* 页分配器使用的水线 */
          long lowmem_reserve[MAX_NR_ZONES];         /* 页分配器使用,当前区域保留多少页不能借给
                                                      高的区域类型 */
          struct pglist_data  *zone_pgdat;          /* 指向内存节点的pglist_data实例 */
          struct per_cpu_pageset __percpu *pageset; /* 每处理器页集合 */
          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];   /* 不同长度的空闲区域 */
    }

3.物理页

每个物理页对应一个page结构体,称为页描述符,内存节点的pglist_data实例的成员node_mem_map指向该内存节点包含的所有物理页的页描述符组成的数组

结构体page的成员flags的布局如下:

| [SECTION] | [NODE] | ZONE | [LAST_CPUPID] | ... | FLAGS |

其中,

  • SECTION是稀疏内存模型中的段编号,
  • NODE是节点编号,
  • ZONE是区域类型,
  • FLAGS是标志位。
  • 内联函数page_to_nid用来得到物理页所属的内存节点的编号
  • page_zonenum用来得到物理页所属的内存区域的类型。
include/linux/mm.h
    static inline int page_to_nid(const struct page *page)
    {
          return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
    }
    static inline enum zone_type page_zonenum(const struct page *page)
    {
          return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK;
    }

头文件“include/linux/mm_types.h”定义了page结构体。

因为物理页的数量很大,所以在page结构体中增加1个成员,可能导致所有page实例占用的内存大幅增加。

为了减少内存消耗,内核努力使page结构体尽可能小,对于不会同时生效的成员,使用联合体这种做法带来的负面影响是page结构体的可读性差

目录
相关文章
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
65 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
5月前
|
存储 C语言
C语言学习记录——动态内存函数介绍(malloc、free、calloc、realloc)
C语言学习记录——动态内存函数介绍(malloc、free、calloc、realloc)
341 1
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
53 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
5月前
|
NoSQL Java Redis
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
84 0
|
5月前
|
缓存 Java
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
50 0
|
5月前
|
编译器 C语言 C++
C语言学习记录——位段(内存分配、位段的跨平台、位段的应用)
C语言学习记录——位段(内存分配、位段的跨平台、位段的应用)
55 0
|
3月前
|
存储 JavaScript 前端开发
学习JavaScript 内存机制
【8月更文挑战第23天】学习JavaScript 内存机制
34 3
|
2月前
|
Linux Shell 虚拟化
使用LiME收集主机物理内存的内容时发生宕机
使用LiME收集主机物理内存的内容时发生宕机
|
2月前
crash —— 获取物理内存布局信息
crash —— 获取物理内存布局信息
|
4月前
|
开发者 Java
JVM内存问题之top命令的物理内存信息中,'used'和'free','avail Mem'分别表示什么
JVM内存问题之top命令的物理内存信息中,'used'和'free','avail Mem'分别表示什么