物理内存组织结构


系统调用mmap

  1. 系统调用mmap用来创建内存映射,把创建内存映射主要工作委托给do_mmap函数,内核源码文件处理 :mm/mmap.c
  2. 虚拟内存区域使用其实地址和结束地址描述,链表按起始地址递增排序。
  3. 红黑树是自动平衡二叉树好处有1.查询方便,2.插入的时候避免全链表扫描
  4. 区别 在于: mmap 指定便宜的单位是字节,而mmap2 指定的单位是页。ARM64架构实现系统调用mmap

    sys_mmap 过程如下: 检查偏移是不是页的整数倍(如果偏移不是页的整数倍,直接返回-EINVAL,如果偏移是页的整数倍,那么把偏移转成页为单位的偏移,然后调用下面函数sys_mmap_pgoff) sys_mmap_pgoff 文件映射(1. SYSCALL_DEFINE1函数中有2.sys_mmap_pgoff调用,主要是根据文件描述符在进程的打开文件表中找到file实例) 匿名巨型页映射(在hugetlbfs文件系统中创建文件“anon_hugepage") vm_mmap_pgoff(以写者身份申请读写信号量) do_mmap(把创建内存映射主要工作直接委托给此函数) get_unmapped_area(根据情况调用特定函数来分配虚拟地址范围) 计算虚拟内存标志 mmap_region(创建虚拟内存区域) may_expand_vm函数以检查进程虚拟内存限制 是否和一些旧的虚拟内存区域重叠-->do_munmap()删除映射 如果有私有的可写映射 可以和已经有的虚拟内存区域合并?是调用vma_merge 不是创建一个新的虚拟内存区域 文件映射--调用call_mmap() 共享的匿名映射-》调用shemem_zero_setup() vma_link 合并链接 vma_set_page_prot (释放读写信号量) 如果调用者要求把页锁定在内存中,或要求填充页表并且允许阻塞,那么函数处理即可,分配物理页,并且在页表中把虚拟页映射到物理页

系统调用munmap

系统调用munmap 用来删除内存映射。它有两个参数:起始地址和长度即可,它的主要工作委托给内核源码文件处理:”mm/mmap.c"当中的函数do_munmap.

vm_munmap
    do_munmap
        vma = find_vma(mm,start);// 根据起始地址找到要删除的第一个虚拟内存区域vma,
        error = _split_vma(mm,vma,start,0);//如果只删除虚拟内存区域vma的部分,那么分裂虚拟区域
        last  = find_vma(mm,end);//根据结束地址找到要删除的最后一个虚拟内存vma
        int error = _split_vma(mm,last,end,1);//如果只删除虚拟内存区域last的一部分,那么分裂虚拟内存区域vma
        munlock_vma_pages_all//针对所有删除目标,如果虚拟内存区域被锁定在内存中(不允许换出到交换区),调用函数解除锁定
        detach_vmas_to_be_unmapped //调用此函数,把所有删除目标从进程虚拟内存区域链表和树中删除,单独组成一条临时的链表。
        unmap_region // 调用此函数,针对所有删除目标,在进程的页表中删除映射,并且从处理器的页表缓存中删除映射。
        arch_unmap //调用此函数执行处理器架构特定的处理操作。
        remove_vma_list //调用此函数,删除所有目标

物理内存组织结构

体系结构

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

  1. 非一致性访问(Non-Unit Memory Access,NUMA):指内存被划分成多个内存节点的多处理器系统,访问一个内存节点花费的时间取决于处理器和内存节点的距离。
  2. 对称多处理器(Symmetric Multi-Processor,SMP):即一致内存访问(Uniform Memory Access,UMA)所有处理器访问内存花费的时间是相同。

NUMA 系统,每个CPU 都有自己的本地内存,可以支持特别快速的访问,各个cpu 之间通过总结链接起来,以支持对其他CPU的本地内存访问,当然比访问本地内存慢一点。

内存模型

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

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

三级结构

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

  1. 内存节点-----》分为两种情况: NUMA体系的内存节点,根据处理器和内存的距离划分。 在具有不连续的NUMA系统中,表示比区域的级别更高的内存区域,根据物理地址是否连续划分,每块物理地址连续的内存是一个内存节点。 pglist_data 结构体内核源码:include/linux/mmzone.h ``` struct bootmem_data; 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 ;//节点标志符

    }

> node_mem_map 此成员指向页描述符数组,每个物理页对应一个页描述符。
Node 是内存管理最顶层的结构,在NUMA架构下,CPU平均划分为多个Node,每个Node有自己的内存控制器及内存插槽,CPU访问自己Node上的内存速度块,
而访问其他CPU锁关联Node的内存速度慢,UMA被当做只一个Node的NUMA系统。

## 内存区域
内存节点被划分为内存区域:  Linux内核源码分析 include/linux/mmzone.h

enum zone_type {

ifdef CONFIG_ZONE_DMA

ZONE_DMA,//Direct Memory Access, 意思是直接内存访问,如果有些设备不能直接访问所有内存,需要使用DMA区域。比如工业标准ISA总线

endif

ifdef CONFIG_ZONE_DMA32

ZONE_DMA32 //64位系统,对4G内存访问支持,既要支持只能直接访问16MB以下的内存设备,又要支持只能直接访问4GB以下的内存的32设备,必须使用此DMA32

endif

ifdef CONFIG_HIGHMEM

ZONE_HIGHMEM // 高端内存区域,此区域是32位时代的产物,内核和用户地址空间按照1:3划分,内核地址空间只有1GB,不能把1GB以上的内存直接映射到内核地址。

endif

ifdef CONFIG_NORMAL

ZONE_NORMAL// 普通区域,直接映射到内核虚拟地址空间的内存区域,又称为普通区域,又称为直接映射区域,又称为线性映射区域

endif

ZONE_MOVABLE//可移动区域,他是一个伪内存区域,用来防止内存碎片 #ifdef CONFIG_ZONE_DEVICE ZONE_DEVICE //为支持持久内存热插拔增加的内存区域,每一个内存去也用一个zone结构体来描述。 #endif

ifndef __GENERATING_BOUNDS_H

struct zone { unsigned long watermark[NR_WMARK];//页分配器使用的水线

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 ;//每处理页集合
unsigned longe zone_start_pfn;// 页起始页号

unsigned long managed_pages ;// 伙伴分配器管理的物理页的数量
unsigned long spanned_pages;//当前区域跨越的总页数,包括空洞
unsigned long present_pages;// 当前区域存在的物理页的数量,不包括空洞
const char *name  //区域名称

struct free_are free_area[MAX_ORDER] //不同长度的空间区域

}

}

## 物理页
每个物理页对应一个page结构体,成为页描述符,内存节点的pglist_data实例的成员node_mem_map指向该内存节点包含的所有物理页的描述符组成的数组,
Linux内核源码分析:include/linux/mm_types.h

struct page { unsigned long flags; union { struct address_space mapping; void s_mem; atomic_t compound_mapcount; } } ```

  1. 页是内存管理当中的最小单位,页面中的内存其物理地址是连续的,每个物理页由struct page 描述。为了节省内存,struct page是个联合体。
  2. 页,又称为页帧,在内核中,内存管理单元MMU(负责虚拟地址和物理地址转换的硬件)是把物理页page 作为内存管理的基本单位。体系结构不同,支持的页大小也想通。
  3. 32位体系结构支持4kb的页
  4. 64位体系结构支持8kb的页
  5. MIPS64架构体系支持16kb的页