一文搞懂linux页框分配与释放
页的分配
1.1 Alloc fast path alloc_pages--->alloc_pages_node--->__alloc_pages_node --->__alloc_pages--->
__alloc_pages_nodemask--->get_page_from_freelist
1.1.1从选定内存域分配页

1,如果oder为0表示分配单页,这个时候就从pcplist中分配(冷热页)
2,如果设置了ALLOC_HARDER表示一次高优先级的分配,就从前一类型为MIGRATE_HIGHATOMIC的链表中分配。MIGRATE_HIGHATOMIC类型的页用于一些紧急情况下的内存分配。
3,如果都不是前面的情况就尝试从指定迁移类型migratetype的链表中去分配
4,如果在指定迁移类型链表中没有仍然没有分配到就尝试从其他迁移类型的链表中去偷取
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)


分配冷热页

到指定迁移类型的伙伴系统链表中分配页
函数__rmqueue_smallest从指定迁移类型migratetype中去分配order阶的页块。如果order阶对应的链表没有空闲块就从更大阶的链表中去分配,将更大的页块拆解将剩余部分挂到对应order的链表中去。
low:为希望分配的阶,high:实际发现有空闲页的阶;area:为high对应的free_area;migratetype:指定的迁移类型
1.1.2 Alloc Fallbacks
查找备用迁移类型
备用迁移类型fallbacks是一个二维数组,表示如果指定迁移类型分配失败,其他可用的迁移类型列表
1.1.3联合页
前面讲解了通过调用函数rmqueue来做页分配,如果分配成功,在返回页之前要对页做一些预处理,比如分配标志gfp_flags中设置了__GFP_COMP请求多个页,就需要将分配到的多个页组合成复合页。第一页称为首页,其余页都是尾页,具体组合逻辑如下:
1.2 Alloc slowpath
前面快速分配内存没有成功下面通过各种途径尝试分配到所需内存,慢速分配步骤如下: 降低水印ALLOC_WMARK_MIN,如果设置了__GFP_KSWAPD_RECLAIM就唤醒交换线程; 调用get_page_from_freelist尝试重新分配; 如果分配的页阶大于0尝试内存压缩,通过内存迁移合并出较大的内存块,然后尝试内存分配; 如果设置了__GFP_KSWAPD_RECLAIM再次唤醒交换线程,确保交换线程不会意外睡去; 直接进行内存回收之后尝试分配; 如果内存回收没有分配到所需内存,就直接进行内存压缩之后尝试分配; 检查分配标志是否存在一些潜在可调的空间,然后再次调用get_page_from_freelist尝试份分配; 如果没有回收到足够的内存就尝试杀死一些进程然后尝试分配内存; 如果仍然没有分配到内存,分配标志中设置了__GFP_NOFAIL就设置ALLOC_HARDER尝试做内存分配。
页的释放

函数free_pages用于释放内存页,传入的参数是页虚拟地址和order。首先函数会根据虚拟地址得到对应的page结构,然后判断order是否为0,如果为0就释放到per cpu lists中去。如果per cpu lists中缓存的页数大于了其上限pcp->high就释放一批pcp->batch到伙伴系统中去。如果order大于0就直接释放到伙伴系统中。
下面是从per cpu lists中释放一批pcp->batch页到伙伴系统中的实现:
伙伴系统
cat /proc/buddyinfo可以看到伙伴系统所有内存域每个阶剩余的页块信息:

cat /proc/pagetypeinfo可以看到每个页阶中所有迁移类型中的页块数:

函数__free_one_page中实现了伙伴系统的核心逻辑:
