在上面一节我们讲述了buddy分配器是如何分配一页的,本节我们在学习buddy分配器是如何释放一页的

分配一页的算法:比如当前释放order=n的页

  • 获得当前释放order=n的页,对应的buddy,也就是兄弟页,俗话说先找到兄弟

    • 找到兄弟buddy了之后,接下来就是看buddy和此页是否可以合并

      • 检查buddy是否是空闲的页(通过检查page→private是否为0)
      • 检查buddy是否和此页是相同的order
      • 检查buddy和此page是否属于同一个zone
      • 检查buddy的引用计数_refcount是否为0
    • 如果上述的条件都符合,则认为此buddy和此page可以合并
    • 将此buddy从lru链表中删除,页的个数减去1
    • 再将order++,从更高的order去寻找buddy,检查是否可以合并
  • 当找不到buddy的时候,则将此order的页加到lru链表中
  • 将order此页的nr_free加1

举例:当释放order=2的页

  • 找到order=2的buddy页,也就是兄弟页
  • 检查此buddy页是否可以和当前释放的页合并
  • 如果可以合并,则order+1=3
  • 则找到order=3的buddy页
  • 检查此buddy页是否可以和需要分配页是否可以合并
  • 如果合并则将order+1=4。 继续检查是否可以合并到最大order
  • 如果当order=4时无法合并,则将此page添加到order=4的freelist中即可。

那怎么获取一个将要释放页的buddy呢,内核提供了一个函数,可以获取buddy的pfn

static inline unsigned long
__find_buddy_pfn(unsigned long page_pfn, unsigned int order)
{return page_pfn ^ (1 << order);
}

我们在zone那一节讲解了page和pfn的关系,这里在复习一下。物理页如果按照4K的大小来描述的话,一个4K大小的物理页的区域我们称之为page frame页帧,而如果给page frame编号的话,就出现了page frame num。

而内核提供的page_to_pfn和pfn_to_page可以轻松的相互转化pfn和page的关系,在内存模型为稀疏模型的情况下,page=vmemmap+pfn

假设当前的order=0, page_pfn=0的话,则对应的buddy_pfn=0^(1<<0)=1,则物理页0和物理页1是buddy,就是好兄弟

假设当前的order=3,  page_pfn=0的话,则对应的buddy_pfn=0^(1<<3)=8,则物理页0和物理页8是buddy,中间刚好是order个页。

说以说可以通过上述的函数来计算出buddy所在的位置

我们接下来看看buddy释放页的核心函数:

static inline void __free_one_page(struct page *page, unsigned long pfn, struct zone *zone, unsigned int order,int migratetype)
{unsigned long combined_pfn;unsigned long uninitialized_var(buddy_pfn);struct page *buddy;unsigned int max_order;struct capture_control *capc = task_capc(zone);max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);VM_BUG_ON(!zone_is_initialized(zone));VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page);VM_BUG_ON(migratetype == -1);if (likely(!is_migrate_isolate(migratetype)))__mod_zone_freepage_state(zone, 1 << order, migratetype);VM_BUG_ON_PAGE(pfn & ((1 << order) - 1), page);VM_BUG_ON_PAGE(bad_range(zone, page), page);continue_merging:while (order < max_order - 1) {if (compaction_capture(capc, page, order, migratetype)) {__mod_zone_freepage_state(zone, -(1 << order),migratetype);return;}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++;}if (max_order < MAX_ORDER) {/* If we are here, it means order is >= pageblock_order.* We want to prevent merge between freepages on isolate* pageblock and normal pageblock. Without this, pageblock* isolation could cause incorrect freepage or CMA accounting.** We don't want to hit this code for the more frequent* low-order merging.*/if (unlikely(has_isolate_pageblock(zone))) {int buddy_mt;buddy_pfn = __find_buddy_pfn(pfn, order);buddy = page + (buddy_pfn - pfn);buddy_mt = get_pageblock_migratetype(buddy);if (migratetype != buddy_mt&& (is_migrate_isolate(migratetype) ||is_migrate_isolate(buddy_mt)))goto done_merging;}max_order++;goto continue_merging;}done_merging:set_page_order(page, order);/** If this is not the largest possible page, check if the buddy* of the next-highest order is free. If it is, it's possible* that pages are being freed that will coalesce soon. In case,* that is happening, add the free page to the tail of the list* so it's less likely to be used soon and more likely to be merged* as a higher order page*/if ((order < MAX_ORDER-2) && pfn_valid_within(buddy_pfn)) {struct page *higher_page, *higher_buddy;combined_pfn = buddy_pfn & pfn;higher_page = page + (combined_pfn - pfn);buddy_pfn = __find_buddy_pfn(combined_pfn, order + 1);higher_buddy = higher_page + (buddy_pfn - combined_pfn);if (pfn_valid_within(buddy_pfn) &&page_is_buddy(higher_page, higher_buddy, order + 1)) {list_add_tail(&page->lru,&zone->free_area[order].free_list[migratetype]);goto out;}}list_add(&page->lru, &zone->free_area[order].free_list[migratetype]);
out:zone->free_area[order].nr_free++;
}
  • 首先会进行一系列合法性检查,zone是否初始化? 迁移类型是否等于-1?  等等
  • 接着就会进入一个while循环,当前order到最大order减去1之间 寻找合适的buddy,然后合并
    1. 根据当前page和pfn,获取buddy的buddy_pfn,根据buddy_pfn在获取buddy页
    2. 通过调用pfn_valid_within来检查buddy_pfn是否是有效的,通过物理地址>>PAGE_SHIFT来判断
    3. 调用page_is_buddy函数来检查此buffy页是否可以合并
      1. page_order(buddy) == order    //buddy的所在order和释放的页的order是否相同
      2. page_zone_id(page) != page_zone_id(buddy)  //检查是都都在一个相同的zone中
      3. page_count(buddy) != 0  //检查buddy页的索引技术是否等于0
    4. 检查到此buddy可以和此page可以完美合并则进行下一步操作
    5. 将buddy页从page的lru链表中删除,同时将此order可用的page数目减去1,设置此buddy页不在buddy系统中
    6. 计算buddy页和释放页合并后的pdn和page,同时将order数目加1
    7. 继续进入到while循环中再次判断,是否有空闲的页可以合并,
    8. 当出现无法找到合适的buddy页时,则调到done_merging进行做最后的收尾
  • set_page_order(page, order);  //设置最终page的order数目
  • 如果当前的order不是最大的order,系统还可以再尝试一波,还是上面相同的操作
  • 将最终合并后的页假如到属于他们order的lru链表中
  • 将此order的可用的页的个数加1

Buddy分配器之释放一页相关推荐

  1. java怎么释放分配的内存,linux 内存的分配和释放,linux分配释放

    linux 内存的分配和释放,linux分配释放 了解内存分配机制(共享映射与请求分页) 通过 pmap 命令,可以获取用户进程逻辑地址空间中映射的内存信息: pmap -x $pid 其中 -x 表 ...

  2. C/C++动态二维数组的内存分配和释放

    C语言: 1 //二维数组动态数组分配和释放 2 //数组指针的内存分配和释放 3 //方法一 4 char (*a)[N];//指向数组的指针 5 a = (char (*)[N])malloc(s ...

  3. OpenCV分配与释放图像空间

     图像处理 单通道图像灰度取值 IplImage * pSrcImage = cvLoadImage("Sunset.jpg",CV_LOAD_IMAGE_GRAYSCALE) ...

  4. 利用二叉树的思想来实现分配和释放内存方法

    虽然大部分系统都有提供内存动态分配和释放函数(即C语言中的malloc和free函数),但是在嵌入式开发中由于系统的限制往往需要自己来实现内存管理,如在有些平台上可动态申请的最大空间不能满足程序设计的 ...

  5. 如何简化临时内存的分配与释放

    描述:在编制 C++ 程序时,最常遇到的一个令人恼火的问题便是临时资源的分配与释放问题, 由于程序的逻辑关系通常很复杂,引发异常的可能性也很多,为了妥善处理运行时异常, 我们不得不在可能引发异常的任何 ...

  6. C++/C--动态二维数组的内存分配与释放【转载】

    1 C语言_二维数组动态数组分配和释放 1.1 数组指针的内存分配和释放 //方法一 char (*a)[N];//指向数组的指针 a = (char (*)[N])malloc(sizeof(cha ...

  7. 分配和释放 BSTR 的内存

    本文档已存档,并且将不进行维护. 分配和释放 BSTR 的内存 Visual Studio .NET 2003                  转自: https://msdn.microsoft. ...

  8. FFmpeg源代码简单分析:内存的分配和释放(av_malloc()、av_free()等)

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  9. C语言中多维数组的内存分配和释放(malloc与free)(转)

    C语言中多维数组的内存分配和释放(malloc与free)(转) 写代码的时候会碰到多维数组的内存分配和释放问题,在分配和释放过程中很容易出现错误.下面贴上一些示例代码,以供参考. 如果要给二维数组( ...

  10. 指针分配和释放空间(转)

    指针分配和释放空间(转) (2012-06-06 12:42:04) 转载▼ 标签: 指针 分类: C/Cplusplus 20.1 理解指针的两种"改变" 普通变量(非指针,简单 ...

最新文章

  1. 如何创建一个用弹出窗口来查看详细信息的超链接列
  2. 初创企业股权架构_初创企业如何以每月不到200美元的价格利用生产级基础架构...
  3. html5+ mui框架 微信授权登录后跳回app无任何回调事件
  4. ESP-12F模块转接板测试版调试说明,下载MicroPython程序。ESP8266-12F
  5. RPC简介及框架选择
  6. Spark(二): 内存管理
  7. PTA--Reversing Linked List
  8. 职教云python程序设计答案_智慧职教云课堂Python程序设计(常州工业职业技术学院)答案公众号...
  9. HackerRank 算法刷题笔记(一),基于Go语言
  10. 这些实用的WhatsApp工具,赶快用起来
  11. 计算机机房空调原理,机房精密空调的工作原理
  12. angularjs 获取复选框的值_如何利用Python批量获取天眼查企业信息?
  13. 说说DBA职责和目标
  14. 《windows游戏编程大师技巧》第五章:DirectX基础知识和令人生畏的COM
  15. 关于12球问题的讨论
  16. jquery-210812-05---jquery函数02
  17. 数据仓库——ODS/stg层数据漂移问题
  18. java小程序计算器_java 小程序 计算器
  19. 图像的放大:双三次插值算法(C++实现)
  20. 计算机cct考试在线答题,【2017年整理】cct一级考试模拟题.ppt

热门文章

  1. python log模块
  2. 一句实现jquery导航栏
  3. 【转】12 TOP Command Examples in Linux
  4. 有限状态机FSM的写法
  5. 线程不安全 静态变量_【高并发】面试官问我:为啥局部变量是线程安全的?...
  6. Kafka副本同步机制理解
  7. 一句代码搞定权限请求,从未如此简单
  8. 怎么用itunes来打开手机软件
  9. 快速预览Office 15服务端:Exchange 2013
  10. 每天进步一点点——mysql——Percona XtraBackup(innobackupex)