Buddy分配器之释放一页
在上面一节我们讲述了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了之后,接下来就是看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,然后合并
- 根据当前page和pfn,获取buddy的buddy_pfn,根据buddy_pfn在获取buddy页
- 通过调用pfn_valid_within来检查buddy_pfn是否是有效的,通过物理地址>>PAGE_SHIFT来判断
- 调用page_is_buddy函数来检查此buffy页是否可以合并
- page_order(buddy) == order //buddy的所在order和释放的页的order是否相同
- page_zone_id(page) != page_zone_id(buddy) //检查是都都在一个相同的zone中
- page_count(buddy) != 0 //检查buddy页的索引技术是否等于0
- 检查到此buddy可以和此page可以完美合并则进行下一步操作
- 将buddy页从page的lru链表中删除,同时将此order可用的page数目减去1,设置此buddy页不在buddy系统中
- 计算buddy页和释放页合并后的pdn和page,同时将order数目加1
- 继续进入到while循环中再次判断,是否有空闲的页可以合并,
- 当出现无法找到合适的buddy页时,则调到done_merging进行做最后的收尾
- set_page_order(page, order); //设置最终page的order数目
- 如果当前的order不是最大的order,系统还可以再尝试一波,还是上面相同的操作
- 将最终合并后的页假如到属于他们order的lru链表中
- 将此order的可用的页的个数加1
Buddy分配器之释放一页相关推荐
- java怎么释放分配的内存,linux 内存的分配和释放,linux分配释放
linux 内存的分配和释放,linux分配释放 了解内存分配机制(共享映射与请求分页) 通过 pmap 命令,可以获取用户进程逻辑地址空间中映射的内存信息: pmap -x $pid 其中 -x 表 ...
- C/C++动态二维数组的内存分配和释放
C语言: 1 //二维数组动态数组分配和释放 2 //数组指针的内存分配和释放 3 //方法一 4 char (*a)[N];//指向数组的指针 5 a = (char (*)[N])malloc(s ...
- OpenCV分配与释放图像空间
图像处理 单通道图像灰度取值 IplImage * pSrcImage = cvLoadImage("Sunset.jpg",CV_LOAD_IMAGE_GRAYSCALE) ...
- 利用二叉树的思想来实现分配和释放内存方法
虽然大部分系统都有提供内存动态分配和释放函数(即C语言中的malloc和free函数),但是在嵌入式开发中由于系统的限制往往需要自己来实现内存管理,如在有些平台上可动态申请的最大空间不能满足程序设计的 ...
- 如何简化临时内存的分配与释放
描述:在编制 C++ 程序时,最常遇到的一个令人恼火的问题便是临时资源的分配与释放问题, 由于程序的逻辑关系通常很复杂,引发异常的可能性也很多,为了妥善处理运行时异常, 我们不得不在可能引发异常的任何 ...
- C++/C--动态二维数组的内存分配与释放【转载】
1 C语言_二维数组动态数组分配和释放 1.1 数组指针的内存分配和释放 //方法一 char (*a)[N];//指向数组的指针 a = (char (*)[N])malloc(sizeof(cha ...
- 分配和释放 BSTR 的内存
本文档已存档,并且将不进行维护. 分配和释放 BSTR 的内存 Visual Studio .NET 2003 转自: https://msdn.microsoft. ...
- FFmpeg源代码简单分析:内存的分配和释放(av_malloc()、av_free()等)
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- C语言中多维数组的内存分配和释放(malloc与free)(转)
C语言中多维数组的内存分配和释放(malloc与free)(转) 写代码的时候会碰到多维数组的内存分配和释放问题,在分配和释放过程中很容易出现错误.下面贴上一些示例代码,以供参考. 如果要给二维数组( ...
- 指针分配和释放空间(转)
指针分配和释放空间(转) (2012-06-06 12:42:04) 转载▼ 标签: 指针 分类: C/Cplusplus 20.1 理解指针的两种"改变" 普通变量(非指针,简单 ...
最新文章
- 如何创建一个用弹出窗口来查看详细信息的超链接列
- 初创企业股权架构_初创企业如何以每月不到200美元的价格利用生产级基础架构...
- html5+ mui框架 微信授权登录后跳回app无任何回调事件
- ESP-12F模块转接板测试版调试说明,下载MicroPython程序。ESP8266-12F
- RPC简介及框架选择
- Spark(二): 内存管理
- PTA--Reversing Linked List
- 职教云python程序设计答案_智慧职教云课堂Python程序设计(常州工业职业技术学院)答案公众号...
- HackerRank 算法刷题笔记(一),基于Go语言
- 这些实用的WhatsApp工具,赶快用起来
- 计算机机房空调原理,机房精密空调的工作原理
- angularjs 获取复选框的值_如何利用Python批量获取天眼查企业信息?
- 说说DBA职责和目标
- 《windows游戏编程大师技巧》第五章:DirectX基础知识和令人生畏的COM
- 关于12球问题的讨论
- jquery-210812-05---jquery函数02
- 数据仓库——ODS/stg层数据漂移问题
- java小程序计算器_java 小程序 计算器
- 图像的放大:双三次插值算法(C++实现)
- 计算机cct考试在线答题,【2017年整理】cct一级考试模拟题.ppt