背景

Read the fucking source code! --By 鲁迅

A picture is worth a thousand words. --By 高尔基

说明:

Kernel版本:4.14

ARM64处理器,Contex-A53,双核

使用工具:Source Insight 3.5, Visio

1. 概述

本文将分析Buddy System。

Buddy System伙伴系统,是通过将物理内存划分为页面来进行管理的系统,支持连续的物理页面分配和释放。此外,使用与碎片相关的算法来确保最大的连续页面。

先通过一个例子大体介绍一下原理吧:

空闲的物理页框按大小分组成0~MAX_ORDER个链表,每个链表存放页框的大小为2的n次幂,其中n在0 ~ MAX_ORDER-1中取值。

假设请求分配2^8 = 256个页框块:

检查n = 8的链表,检查是否有空闲块,找到了则直接返回;

没有找到满足需求的,则查找n = 9的链表,找到512大小空闲块,拆分成两个256大小块,将其中一个256大小块返回,另一个256大小块添加到n = 8的链表中;

在n = 9的链表中没有找到合适的块,则查找n = 10的链表,找到1024大小空闲块,将其拆分成512 + 256 + 256大小的块,返回需要获取的256大小的块,将剩下的512大小块插入n = 9链表中,剩下的256大小块插入n = 8的链表中;

合并过程是上述流程的逆过程,试图将大小相等的Buddy块进行合并成单独的块,并且会迭代合并下去,尝试合并成更大的块。合并需要满足要求:

两个Buddy块大小一致;

它们的物理地址连续;

第一个Buddy块的起始地址为 (2 x N x 4K)的整数倍,其中4K为页面大小,N为Buddy块的大小;

struct page结构中,与Buddy System相关的字段有:

_mapcount: 用于标记page是否处在Buddy System中,设置成-1或PAGE_BUDDY_MAPCOUNT_VALUE(-128);

private: 一个2^k次幂的空闲块的第一个页描述符中,private字段存放了块的order值,也就是k值;

index: 存放MIGRATE类型;

_refcount: 用户使用计数值,没有用户使用为0,有使用的话则增加;

合并时如下图所示:

2. Buddy页面分配

Buddy页面分配的流程如下图所示:

从上图中可以看出,在页面进行分配的时候,有以下四个步骤:

如果申请的是order = 0的页面,直接选择从pcp中进行分配,并直接退出;

order > 0时,如果分配标志中设置了ALLOC_HARDER,则从free_list[MIGRATE_HIGHATOMIC]的链表中进行页面分配,分配成功则返回;

前两个条件都不满足,则在正常的free_list[MIGRATE_*]中进行分配,分配成功则直接则返回;

如果3中分配失败了,则查找后备类型fallbacks[MIGRATE_TYPES][4],并将查找到的页面移动到所需的MIGRATE类型中,移动成功后,重新尝试分配;

如下图:

上述分配的过程,前3个步骤都会调用到__rmqueue_smallest,第4步调用__rmqueue_fallback,将从这两个函数来分析。

2.1 __rmqueue_smallest

__rmqueue_smallest的源代码比较简单,贴上来看看吧:

static inline

struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,

int migratetype)

{

unsigned int current_order;

struct free_area *area;

struct page *page;

/* Find a page of the appropriate size in the preferred list */

for (current_order = order; current_order < MAX_ORDER; ++current_order) {

area = &(zone->free_area[current_order]);

page = list_first_entry_or_null(&area->free_list[migratetype],

struct page, lru);

if (!page)

continue;

list_del(&page->lru);

rmv_page_order(page);

area->nr_free--;

expand(zone, page, order, current_order, area, migratetype);

set_pcppage_migratetype(page, migratetype);

return page;

}

return NULL;

}

从代码中可以看出:

从申请的order大小开始查找目标MIGRATE类型链表中页表,如果没有找到,则从更大的order中查找,直到MAX_ORDER;

查找到页表之后,从对应的链表中删除掉,并调用expand函数进行处理;

expand函数的处理逻辑就跟本文概述中讲的例子一样,当在大的order链表中申请到了内存后,剩余部分会插入到其他的order链表中,来一张图就清晰了:

2.2 __rmqueue_fallback

当上述过程没有分配到内存时,便会开始从后备迁移类型中进行分配。

其中,定义了一个全局的二维fallbacks的数组,并根据该数组进行查找,代码如下:

/*

* This array describes the order lists are fallen back to when

* the free lists for the desirable migrate type are depleted

*/

static int fallbacks[MIGRATE_TYPES][4] = {

[MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_TYPES },

[MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_TYPES },

[MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_TYPES },

#ifdef CONFIG_CMA

[MIGRATE_CMA] = { MIGRATE_TYPES }, /* Never used */

#endif

#ifdef CONFIG_MEMORY_ISOLATION

[MIGRATE_ISOLATE] = { MIGRATE_TYPES }, /* Never used */

#endif

};

__rmqueue_fallback完成的主要工作就是从后备fallbacks中找到一个迁移类型页面块,将其移动到目标类型中,并重新进行分配。

下图将示例整个流程:

3. Buddy页面释放

页面释放是申请的逆过程,相对来说要简单不少,先看一下函数调用图吧:

当order = 0时,会使用Per-CPU Page Frame来释放,其中:

MIGRATE_UNMOVABLE, MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE三个按原来的类型释放;

MIGRATE_CMA, MIGRATE_HIGHATOMIC类型释放到MIGRATE_UNMOVABLE类型中;

MIGRATE_ISOLATE类型释放到Buddy系统中;

此外,在PCP释放的过程中,发生溢出时,会调用free_pcppages_bulk()来返回给Buddy系统。来一张图就清晰了:

在整个释放过程中,核心函数为__free_one_page,该函数的核心逻辑部分如下所示:

continue_merging:

while (order < max_order - 1) {

buddy_pfn = __find_buddy_pfn(pfn, order);

buddy = page + (buddy_pfn - pfn);

if (!pfn_valid_within(buddy_pfn))

goto done_merging;

if (!page_is_buddy(page, buddy, order))

goto done_merging;

/*

* Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,

* merge with it and move up one order.

*/

if (page_is_guard(buddy)) {

clear_page_guard(zone, buddy, order, migratetype);

} else {

list_del(&buddy->lru);

zone->free_area[order].nr_free--;

rmv_page_order(buddy);

}

combined_pfn = buddy_pfn & pfn;

page = page + (combined_pfn - pfn);

pfn = combined_pfn;

order++;

}

__find_buddy_pfn: 根据释放页面的pfn计算对应的buddy_pfn,比如pfn = 0x1000, order = 3,则buddy_pfn = 0x1008,pfn = 0x1008, order = 3,则buddy_pfn = 0x1000;

page_is_buddy:将page和buddy进行配对处理,判断是否能配对;

进行combine之后,再将pfn指向合并后的开始位置,继续往上一阶进行合并处理;

按照惯例,再来张图片吧:

不得不说,还有很多细节没有去扣,一旦沉沦,将难以自拔,待续吧。

Linux is内存管理,【原创】(七)Linux内存管理相关推荐

  1. wordpress后台管理(七)说说管理:所有说说、发表说说

    查看全文 http://www.taodudu.cc/news/show-4422015.html 相关文章: QQ发表说说显示服务器超时,qq空间发表说说无法显示的原因 wordpress后台管理( ...

  2. linux源代码解读,【原创】Linux MM 源代码解读 (1)

    最近转载了不少文章,自己也读了ULK3 MM章节数遍,小有体会.写一些心得,以免自己忘记. 之前一些virtual address到physical address的映射的基本MM机制,可以参看博客转 ...

  3. linux io映射,【原创】Linux 文件系统移植全解密以linux-2.6.35内核源码为例说明一下IO静态映射的过程...

    最近不断有人跟我说起静态映射的问题,今天就以linux-2.6.35内核源码为例说明一下IO静态映射的过程(ARM平台). //init/main.c asmlinkage void __init s ...

  4. wordpress后台管理(七)说说管理:发表说说、所有说说

    目录 第一章.简介 第二章.发表说说 第三章.所有说说 第一章.简介 什么是说说?相当于我们发个朋友圈一样,记录生活中的.工作中等有趣的事情. 我网站导航中没有添加"说说"这一栏, ...

  5. linux cma内存,【原创】(十六)Linux内存管理之CMA,

    [原创](十六)Linux内存管理之CMA, 背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. ...

  6. 显卡 内存分配 linux,【原创】Linux环境下的图形系统和AMD R600显卡编程(4)——AMD显卡显存管理机制...

    显卡使用的内存分为两部分,一部分是显卡自带的显存称为VRAM内存,另外一部分是系统主存称为GTT内存(graphics translation table和后面的GART含义相同,都是指显卡的页表,G ...

  7. linux内存管理(七)-slab分配器

    linux内存三大分配器:引导内存分配器,伙伴分配器,slab分配器 三.slab分配器 Linux内核中基于伙伴算法实现的分区页框分配器适合大块内存的请求,它所分配的内存区是以页框为基本单位的.有时 ...

  8. Linux内存管理之高端内存映射

    一:引子 我们在前面分析过,在linux内存管理中,内核使用3G->4G的地址空间,总共1G的大小.而且有一部份用来做非连续空间的物理映射(vmalloc).除掉这部份空间之外,只留下896M大 ...

  9. linux内存管理(一)-内存管理架构

    文章目录 一.内存管理架构 二.虚拟地址空间布局架构 2.1内核地址空间布局 2.2用户地址空间布局 三.物理内存体系架构 3.1 正常内存 3.2 设备内存 四.内存结构 五.内存模型 六.虚拟地址 ...

  10. Linux 操作系统原理 — 内存 — 页式管理、段式管理与段页式管理

    目录 文章目录 目录 前文列表 页式管理 快表 多级页表 基于页表的虚实地址转换原理 应用 TLB 快表提升虚实地址转换速度 页式虚拟存储器工作的全过程 缺页中断 为什么 Linux 默认页大小是 4 ...

最新文章

  1. 创建UITextField对象
  2. 信号量 互斥量 条件变量
  3. 独家 | 2019 ICCV 收录论文:基于弱监督学习的病理影像分析框架
  4. 如何在AxureRP7中使用FontAwesome字体
  5. html multiply属性,NonCommutativeMultiply
  6. 摄影技巧的种类之一             ——街拍技巧
  7. 机房收费系统重构版:那个系统我们一起遇到的问题
  8. linux清理内存的命令
  9. java中包的概念及作用_Java中包的概念和使用实战
  10. 【神仙打架】特奖答辩前10出炉,两名CS学生3篇顶会一作,有人周读3000页英文论文...
  11. zabbix(三)—— update
  12. mongodb linux用户验证登陆,转载:linux下mongodb的用户查询_【Linux】MongoDB创建数据库(开启用户认证)...
  13. [病毒木马] LSP劫持
  14. 决策树分析,让你的风险应对更专业
  15. [渝粤教育] 中央财经大学 保险学概论 参考 资料
  16. input range: vue自定义进度条
  17. 酒水知识(六大基酒之威士忌_Whisky)
  18. steamlit安装
  19. 华为很快搭载鸿蒙系统,华为高管确认很快将会推出搭载鸿蒙操作系统的智能手表...
  20. Rust 中的指针:Box、Rc、Cell、RefCell

热门文章

  1. Windows系统下gpu版tensorflow+anaconda3安装经验
  2. 凡科建站产品体验报告
  3. matlab填充封闭包含区域,求指导matlab怎么填充曲线构成的封闭区域
  4. 百度AI使用方案:黑白图片上色
  5. 法律权利与法律义务的二重性
  6. Time Gen使用-------------绘制时序电路波形
  7. 图形学实验 警察抓小偷
  8. invoker 祈求者 c++ 题解
  9. windows64位配置安装python2.7
  10. 代码管理工具之SVN