【原创】(六)Linux内存管理 - zoned page frame allocator - 1
背景
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. 介绍
之前的系列内存管理文章基本上描述的是物理页面的初始化过程,以及虚拟页面到物理页面的映射建立过程,从这篇文章开始,真正要涉及到页面的分配了。接下来的文章会围绕着分区页框分配器(zoned page frame allocator)
来展开,其中会包含大家熟知的Buddy System
分析。
本文会先围绕着涉及到的数据结构,以及大体的流程做一个整体的分析,后续会针对这个流程中的细节进行更详细的拆解,我已经迫不及待了。
2. 数据结构
2.1 概述
先回顾一下(五)Linux内存管理zone_sizes_init的数据结构图:
上述的结构体,描述的是下面这张图:
Node ---> ZONE ---> Page
的组织关系,其中Buddy System
中,页面都是以2的次幂来组织成链表,比如free_area[0]
,对应的是1个page
链表,其中又根据不同的MIGRATE_xxxx
类型来组织,如下图:
ARM64
中MAX_ORDER
默认值为11,PAGE_SIZE=4K
,因此总共有0 ~ 10
11个链表数组,链表中的连续的页面为2^0 ~ 2^10
,对应大小为4K ~ 4M
。
可以通过cat /proc/pagetypeinfo
来查看下系统的页面信息,如下图:
可以通过cat /proc/zoneinfo
来查看Node
的ZONE
计数信息:
2.2 Migrate类型
从上边的图中可以看到MIGRATE_xxx
不同的迁移类型,表明页面的移动属性,并在可能的情况下通过将相同属性的页面分组在一起来抑制内存的连续碎片。
enum migratetype {
MIGRATE_UNMOVABLE,
MIGRATE_MOVABLE,
MIGRATE_RECLAIMABLE,
MIGRATE_PCPTYPES, /* the number of types on the pcp lists */
MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES,
#ifdef CONFIG_CMA
/*
* MIGRATE_CMA migration type is designed to mimic the way
* ZONE_MOVABLE works. Only movable pages can be allocated
* from MIGRATE_CMA pageblocks and page allocator never
* implicitly change migration type of MIGRATE_CMA pageblock.
*
* The way to use it is to change migratetype of a range of
* pageblocks to MIGRATE_CMA which can be done by
* __free_pageblock_cma() function. What is important though
* is that a range of pageblocks must be aligned to
* MAX_ORDER_NR_PAGES should biggest page be bigger then
* a single pageblock.
*/
MIGRATE_CMA,
#endif
#ifdef CONFIG_MEMORY_ISOLATION
MIGRATE_ISOLATE, /* can't allocate from here */
#endif
MIGRATE_TYPES
};
MIGRATE_UNMOVABLE
:无法移动和检索的类型,用于内核分配的页面,I/O缓冲区,内核堆栈等;MIGRATE_MOVABLE
:当需要大的连续内存时,通过移动当前使用的页面来尽可能防止碎片,用于分配用户内存;MIGRATE_RECLAIMABLE
:当没有可用内存时使用此类型;MIGRATE_HIGHATOMIC
:减少原子分配请求无法进行高阶页面分配的可能,内核会提前准备一个页面块;MIGRATE_CMA
:页面类型由CMA内存分配器单独管理;MIGRATE_ISOLATE
:内核会暂时更改为这种类型,以迁移使用中的系列活动页面;
2.3 __GFP_xxx请求标志(gfp_mask)
__GFP_xxx
为内部使用的标志,在include/linux/gfp.h
文件中,外部不应该使用这些Flag,这些标志在页面申请的时候使用,其中GFP
表示get free page
。
罗列部分如下:
__GFP_DMA
:请求在ZONE_DMA
区域中分配页面;__GFP_HIGHMEM
:请求在ZONE_HIGHMEM
区域中分配页面;__GFP_MOVABLE
:ZONE_MOVALBE
可用时在该区域分配页面,同时表示页面分配后可以在内存压缩时进行迁移,也能进行回收;__GFP_RECLAIMABLE
:请求分配到可恢复页面;__GFP_HIGH
:高优先级处理请求;__GFP_IO
:请求在分配期间进行I/O操作;__GFP_FS
:请求在分配期间进行文件系统调用;__GFP_ZERO
:请求将分配的区域初始化为0;__GFP_NOFAIL
:不允许请求失败,会无限重试;__GFP_NORETRY
:请求不重试内存分配请求;
2.4 ALLOC_xxxx分配标志(alloc_flags)
分配标志定义在mm/internal.h
文件中,在页面的分配函数中与gfp_mask
分开使用,这些标志时用于内部函数的分配。
ALLOC_WMARK_MIN
:仅在最小水位water mark
及以上限制页面分配;ALLOC_WMARK_LOW
:仅在低水位water mark
及以上限制页面分配;ALLOC_WMARK_HIGH
:仅在高水位water mark
及以上限制页面分配;ALLOC_HARDER
:努力分配,一般在gfp_mask
设置了__GFP_ATOMIC
时会使用;ALLOC_HIGH
:高优先级分配,一般在gfp_mask
设置了__GFP_HIGH
时使用;ALLOC_CPUSET
:检查是否为正确的cpuset;ALLOC_CMA
:允许从CMA区域进行分配;
2.5 struct alloc_context
在页面分配的过程中,有一个结构叫struct alloc_context
,这个结构用于存储各个函数之间传递的参数。这种思想在平时的coding中是可以去借鉴的,比如有些人写代码很喜欢用全局变量,改成这种context
的形式,在各个函数之间传递显得更为优雅。直接看代码吧:
/*
* Structure for holding the mostly immutable allocation parameters passed
* between functions involved in allocations, including the alloc_pages*
* family of functions.
*
* nodemask, migratetype and high_zoneidx are initialized only once in
* __alloc_pages_nodemask() and then never change.
*
* zonelist, preferred_zone and classzone_idx are set first in
* __alloc_pages_nodemask() for the fast path, and might be later changed
* in __alloc_pages_slowpath(). All other functions pass the whole strucure
* by a const pointer.
*/
struct alloc_context {
struct zonelist *zonelist;
nodemask_t *nodemask;
struct zoneref *preferred_zoneref;
int migratetype;
enum zone_type high_zoneidx;
bool spread_dirty_pages;
};
zonelist
:用于分配页面的区域列表;nodemask
:指定Node,如果没有指定,则在所有节点中进行分配;preferred_zone
:指定要在快速路径中首先分配的区域,在慢路径中指定了zonelist
中的第一个可用区域;migratetype
:要分配的迁移页面类型;high_zoneidx
:将分配限制为小于区域列表中指定的高区域;spread_dirty_pages
:脏区平衡相关;
3. build_all_zonelists
在上篇文章中描述到各个zone
,实际上各个zone
最终组织起来是在build_all_zonelists
函数中实现的:
整体完成的工作也比较简单,将所有Node
中可用的zone
全部添加到各个Node
中的zonelist
中,也就是对应的struct pglist_data
结构体中的struct zonelist node_zonelists
字段。
这一步之后,准备工作基本就绪,进行页面申请的工作就可以开始了。
4. alloc_pages
下面的流程开始真正的页面申请了,在内部的实现中通过__alloc_pages
来实现的:
在页面分配时,有两种路径可以选择,如果在快速路径中分配成功了,则直接返回分配的页面;快速路径分配失败则选择慢速路径来进行分配。
4.1 Fast Path
快速路径分配,是通过get_page_from_freelist
来完成的,具体的流程及分析如下图所示:
4.2 Slow Path
慢速路径分配,最终也会调用get_page_from_freelist
,流程分析如下:
【原创】(六)Linux内存管理 - zoned page frame allocator - 1的更多相关文章
- 【原创】(八)Linux内存管理 - zoned page frame allocator - 3
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- 【原创】(七)Linux内存管理 - zoned page frame allocator - 2
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- 【原创】(九)Linux内存管理 - zoned page frame allocator - 4
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- 【原创】(十)Linux内存管理 - zoned page frame allocator - 5
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- Linux内存管理 (11)page引用计数
专题:Linux内存管理专题 关键词:struct page._count._mapcount.PG_locked/PG_referenced/PG_active/PG_dirty等. Linux的内 ...
- 【原创】(十四)Linux内存管理之page fault处理
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- Linux内存管理6---伙伴算法与slab
1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...
- [转帖]Linux分页机制之概述--Linux内存管理(六)
Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...
- Linux内存描述之内存页面page–Linux内存管理(四)
服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...
随机推荐
- Windows平台python验证码识别
参考: http://oatest.dragonbravo.com/Authenticate/SignIn?returnUrl=%2f http://drops.wooyun.org/tips/631 ...
- BZOJ3170 [Tjoi2013]松鼠聚会 切比雪夫距离 - 曼哈顿距离 - 前缀和
BZOJ3170 题意: 有N个小松鼠,它们的家用一个点x,y表示,两个点的距离定义为:点(x,y)和它周围的8个点即上下左右四个点和对角的四个点,距离为1.现在N个松鼠要走到一个松鼠家去,求走过的最 ...
- codeforce #505D - Recovering BST 区间DP
1025D 题意: 有一个递增序列,问能不能构建出一颗每条边的端点值都不互质的二叉排序树. 思路: 区间DP,但是和常见的区间DP不一样, 这里dp[i][j]表示的是区间[i,j]能否以i为根建立一 ...
- CF - 652 D Nested Segments
题目传送门 题解: 可以将所有线段按照左端点优先小,其次右端点优先大进行排序. 然后对于第 i 条线段来说, 那么第 i+1 ---- n 的线段左端点都一定在第i条线段的右边, 接下来就需要知道 i ...
- 洛谷P1661 & yzoj 1650 扩散 题解
题意 先讲一下一种容易陷入误区错误思路 要使时间最小,就去找相对于每个点的最短曼哈顿距离,然后取最大值,时间就是(maxn+1)/2. 代码 #include<cstring> #incl ...
- 【转】Android CTS 测试
http://blog.csdn.net/zxm317122667/article/details/8508013 Android-CTS 4.0.3测试基本配置 1. Download CTS CT ...
- 蚂蚁SOFA系列(2) - SOFABoot的Readiness健康检查机制
作者:404,公众号404P,转载请注明出处. 前言 SOFABoot是蚂蚁金服的开源框架,在原有Spring Boot的基础上增强了不少能力,例如Readiness Check,类隔离,日志空间隔离 ...
- 使用Nginx实现负载均衡(tomcat集群之后实现交叉访问)
tomcat集群(多一台服务器),使用nginx实现负载均衡(upstream sina中配置即可):使用上次博客中的sina案例 1.首先再加一个tomcat服务: 2.修改server.xml配置 ...
- FreeSql (十三)更新数据时忽略列
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...
- FreeSql (二十九)Lambda 表达式
FreeSql 支持功能丰富的表达式函数解析,方便程序员在不了解数据库函数的情况下编写代码.这是 FreeSql 非常特色的功能之一,深入细化函数解析尽量做到满意,所支持的类型基本都可以使用对应的表达 ...