Day41-回顾物理内存管理

欢迎关注微信公众号:qiubinwei-1986

内存架构UMA和NUMA

内存数据结构

物理内存映射

页表初始化函数,在内核使用内存前,需要初始化内核的页表,paging_init函数主要做两次映射:

map_kernel(): 映射内核映像到内核空间的虚拟地址

map_mem(): 做物理内存的线性映射

两者都是建立物理内存到内核空间虚拟地址的线性映射,但是映射的地址不一样。

map_kernel()函数

对内核映像的各个段分别进行映射,映射到内核空间的虚拟地址为vmalloc区域。vmalloc区域的范围从0xFFFF 000 1000 0000 到 0xFFFF 7DFF BFFF 0000

映射如下内容:

代码段:从_text到_etext

只读数据段:从__start_rodata到__inittext_begin

初始化代码段:从__inittext_begin到__inittext_end

初始化数据段:从__initdata_begin到__inittext_end

数据段:从_data到_end

map_mem()函数

会映射三段物理内存到线性映射区。范围从0XFFFF 8000 0000 0000 到0xFFFF FFFF FFFF FFFF

映射第一段物理内存:从0x4000 0000 到0x4008 0000

映射第二段物理内存:从内核映像结束(_end)到物理内存结束(如256GB,最大不超过128TB)

映射第三段物理内存:从内核映像开始(_start)到内核映像结束(_end)

zone初始化

Linux的内核采用内存管理区(zone)的方式进行页面管理。

zone经常会被访问,因此这个数据结构要求以L1高速缓存对齐。

ZONE_PADDING()函数让zone->lock和zone->lru_lock两个热门锁可以分布在不同的高速缓存行中,一个node对应的zone有限,因此zone数据结构不需要关注数据结构的大小。

zone结构体源码解析及部分数据成员解析:

  • _watermark:每个zone启动时会计算3个水位,分别是最低警戒水位(WMARK_MIN),低水位(WMARK_LOW)和高水位(WMARK_HIGH),这个会在页面分配器和kswapd页面回收中用到。

  • lowmem_reserve:防止页面分配器过度使用低端zone的内存

  • zone_pgdat:指向内存节点

  • pageset:用于维护每个CPU上的一系列页面,减少自旋锁的争用

  • zone_start_pfn:zone的起始页帧号

  • managed_pages:zone中被伙伴系统管理的的页面数量

  • spanned_pages:zone包含的页面数量

  • present_pages:zone中实际管理的页面数量,在一些架构下,应该和spanned_pages一致

  • free_area:伙伴系统的核心数据结构,管理空闲页块(page block)链表的数组

  • lock:并行访问时用于保护zone的自旋锁

  • lru_lock:并行访问时用于保护zone中LRU链表的自旋锁。在Linux5.0已经转移到pglist_data中

  • lruvec:LRU链表集合

  • vm_stat:zone计数值。在Linux5.0内核中,该成员已经转移到pglist_data中

struct zone {    /* Read-mostly fields */    /* zone watermarks, access with *_wmark_pages(zone) macros */    unsigned long _watermark[NR_WMARK]; // 页分配器使用的水位线    unsigned long watermark_boost;    unsigned long nr_reserved_highatomic;    long lowmem_reserve[MAX_NR_ZONES]; // 页分配器使用,当前区域保留多少页不能借给高区域类型。...    struct pglist_data  *zone_pgdat;  // 指向内存节点的pglist_data实例    struct per_cpu_pageset __percpu *pageset;  // 用于维护每个CPU上的一系列页面,减少自旋锁的征用...    unsigned long       zone_start_pfn;  // 当前区域的起始物理页号    atomic_long_t       managed_pages;  // 伙伴分配器管理的物理页的数量    unsigned long       spanned_pages;  // 当前区域跨越的总页数,包括空洞    unsigned long       present_pages;  // 当前区域存在的物理页的数量,不包括空洞    const char      *name;  //区域名称    struct free_area    free_area[MAX_ORDER];  // 不同长度的空间区域...    spinlock_t      lock;  //并行访问时用于保护zone的自旋锁    /* Write-intensive fields used by compaction and vmstats. */    struct lruvec      __lruvec;    ZONE_PADDING(_pad2_)...    ZONE_PADDING(_pad3_)    /* Zone statistics */    atomic_long_t       vm_stat[NR_VM_ZONE_STAT_ITEMS];  //zone计数值。在Linux5.0内核中,该成员已经转移到pglist_data中    atomic_long_t       vm_numa_stat[NR_VM_NUMA_STAT_ITEMS];} ____cacheline_internodealigned_in_smp;

zone类型

如前文提到,在64位操作系统下,zone分为ZONE_DMA,ZONE_DMA32, ZONE_NORMAL三个类型(ZONE_HIGHMEM只存在32位操作系统)

enum zone_type {#ifdef CONFIG_ZONE_DMA   // Direct Memory Access,内存直接访问。                         // 有些设备不能直接访问所有内存,需要访问DMA区域    ZONE_DMA,#endif#ifdef CONFIG_ZONE_DMA32 // 64位系统,如果既要支持只能直接访问16MB以下内存设备                         // 又要支持只能直接访问4GB以下32位设备,必须使用该区域DMA32    ZONE_DMA32,#endif    /*     * Normal addressable memory is in ZONE_NORMAL. DMA operations can be     * performed on pages in ZONE_NORMAL if the DMA devices support     * transfers to all addressable memory.     */    ZONE_NORMAL,     // 直接映射到内核虚拟地址空间的内存区域,又称为普通区域、直接映射区、线性映射区#ifdef CONFIG_HIGHMEM  //此区域是32位的产物,内核和用户地址空间按1:3划分#endif    ZONE_MOVABLE,  //可移动区域,是一个伪内存区域,防止内存碎片#ifdef CONFIG_ZONE_DEVICE    ZONE_DEVICE,   //设备区,为支持持久内存热插拔增加的内存区#endif    __MAX_NR_ZONES

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值