linux内存管理系列——伙伴分配器

系统内核初始完毕后,使用页分配器管理物理页,使用的页分配器是伙伴分配器,特点是算法简单高效。

1. 分区的伙伴分配器

1.1 概念

  • 页块(page block):连续的物理页。
  • 阶(order): 伙伴分配器的专业术语,页的数量单位。2^n 个连续页为n阶页块。
  • 伙伴: 满足以下两个n阶页块称为伙伴
    • 两个页块是相邻的,即物理地址是连续的。
    • 页块的第一页的物理页必须的2^n的整数倍。
    • 如果合并成(n + 1)阶页块,第一页的物理页号必须是2^(n + 1) 的整数倍。

1.2 分配n阶页块过程

伙伴分配器分配和释放物理页的数量单位为阶。

1.3 分区伙伴分配器

内核在基本的伙伴分配器基础上改进扩展,支持内存节点和区域,称为分区的伙伴分配器(zone buddy allocator);为了预防内存碎片,把物理根据可移动性分组;针对分配,单页做了性能优化,为了减少处理器之间的锁竞争,在内存区域增加1个每处理器页集合。

1.3.1 数据结构

分区的伙伴分配器专注于某个内存节点的某个区域,内存区域的结构体成员free_area用来维护空闲页块,数组下标对应页块的阶数。
源码分析:
image.png
image.png

image.png
free_area结构:
image.png

1.3.2 根据分配标志获取首选区域类型

申请页时,最低4个标志位用来指定首选内存区域类型。源码如下:
标志组合:
image.png
内存区域类型:
image.png
内核使用宏GFP_ZONE_TABLE定义了标志组合到区域类型的映射表,其中GFP_ZONES_SHIFT是区域类型占用的位数,GFP_ZONE_TABLE把每种标志组合映射到32位整数的某个位置,偏移是(标志组合*区域类型位数),从这个偏移开始的GFP_ZONES_SHIFT个二进制位存放区域类型。编译器编译阶段已经优化计算出结果。
image.png

1.3.3 备用区域列表

如果首选的内存节点区域不能满足分配的请求,可以从备用的内存区域借用物理页。借用必须遵守相应的规则。

  • 一个内存节点的某个区域类型可以从另一个内存节点的相同区域类型借用物理页,比如节点0的普通区域可以从节点1的普通区域借用物理页。
  • 高区域类型可以从低区域类型借用物理页,比如普通区域可以从DMA区域借用物理页;
  • 低区域类型不能从高区域类型借用物理页。比如DMA区域不能从普通区域借用物理页。

内存节点的pg_data_t实例已定义备用区域列表,源码如下:
image.png
image.png
image.png
UMA系统只有一个备用区域列表,按区域类型从高到低排序。假设UMA系统包含普通区域和DMA区域,那么备用区域列表:{普通区域, DMA区域}。UMA系统每个内存节点有两个备用区域列表:一个包含所有内存节点的区域,另一个只包含当前内存节点的区域。
包含所有内存节点的备用区域列表有两种排序方法:

  • 节点优先顺序:先根据节点距离从小到大排序,在每个节点里面根据区域类型从高到低排序。优点是优先选择距离近的内存,缺点是在高区域耗尽以前使用的低区域。
  • 区域优先顺序:先根据区域类型从高到低排序,然后再每个区域类型里面根据节点距离从小到大排序。优点是减少低区域耗尽的概率,缺点是不能保证优先选择距离近的内存。
  • 默认的排序方法会自动选择最优的排序方法:比如64位系统,因为需要DMA和DMA32区域的备用相对少,所以选择节点优先顺序;如果是32位系统,选择区域优先顺序。
1.3.4 区域水线

首选的内存区域什么情况下会从备用区域借用物理页呢?每个内存区域有3个水线。

  • 高水线(high): 如果内存区域的空闲页数大于高水线,说明内存区域的内存充足;
  • 低水线(low): 如果内存区域的空闲页数小于低水线,说明内存区域的内存轻微不足;
  • 最低水线(min): 如果内存区域的空闲页数小于最低水线,说明内存区域的内存严重不足。最低水线以下的内存称为紧急保留内存,在内存严重不足的紧急情况下,给承诺“分给我们少量的紧急保留内存使用,我可以释放更多的内存”的进程使用。

数据结构如下:
image.png
image.png
image.png
image.png

1.3.5 watermark水位控制

内核源码重要数据参数

三个水位值如何计算出来?

unsigned long		managed_pages;  // 伙伴分配器管理的物理页的数量
// 代表的是zone中的所有页,包含空洞,计算公式:zone_end_pfn-zone_start_pfn
unsigned long		spanned_pages;  // 当前区域跨越的总页数,包括空洞
// 代表zone中可用的所有物理页,计算公式:spanned_pages-hole_pages
unsigned long		present_pages;  // 当前区域存在的物理页的数量,不包括空洞
// 代表通过buddy管理所有可用的页,计算公式:present_pages-reserved_+pages

三者之间的关系?
spanned_pages > present_pages > managed_pages
image.png
image.png
image.png

  • min_free_kbytes 代表的是系统保留空闲内存的最低限。watermark[WMARK_MIN]的值是通过min_free_kbytes计算出来的。

image.png
image.png

image.png

2. 分配页

linux内核中,所有分配页的函数最终都会调用到_alloc_pages_nodemask,此函数为分区的伙伴分配器的心脏。
算法流程:

  • 根据分配标志为得到首选区域类型和迁移类型;
  • 执行快速路径,使用低水线尝试第一次分配;
  • 如果快速路径分配失败,才执行慢速路径。

2.1 核心函数

2.1.1 分配标志位分析

image.png
image.png

2.1.2 快速路径调用函数

image.png
image.png
image.png
image.png

2.1.3 慢速路径调用函数

image.png
image.png
image.png
image.png
image.png
image.png

3. 释放页

页分配器提供的释放接口,源码如下:
image.png

参考

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习:https://course.0voice.com/v1/course/intro?courseId=5&agentId=0

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值