【原创】(六)Linux内存管理 - zoned page frame allocator - 1

时间:2023-01-12 22:48:19

背景

  • Read the fucking source code! --By 鲁迅
  • A picture is worth a thousand words. --By 高尔基

说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

1. 介绍

之前的系列内存管理文章基本上描述的是物理页面的初始化过程,以及虚拟页面到物理页面的映射建立过程,从这篇文章开始,真正要涉及到页面的分配了。接下来的文章会围绕着分区页框分配器(zoned page frame allocator)来展开,其中会包含大家熟知的Buddy System分析。

本文会先围绕着涉及到的数据结构,以及大体的流程做一个整体的分析,后续会针对这个流程中的细节进行更详细的拆解,我已经迫不及待了。

2. 数据结构

2.1 概述

先回顾一下(五)Linux内存管理zone_sizes_init的数据结构图:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

上述的结构体,描述的是下面这张图:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

Node ---> ZONE ---> Page的组织关系,其中Buddy System中,页面都是以2的次幂来组织成链表,比如free_area[0],对应的是1个page链表,其中又根据不同的MIGRATE_xxxx类型来组织,如下图:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

ARM64MAX_ORDER默认值为11,PAGE_SIZE=4K,因此总共有0 ~ 1011个链表数组,链表中的连续的页面为2^0 ~ 2^10,对应大小为4K ~ 4M

可以通过cat /proc/pagetypeinfo来查看下系统的页面信息,如下图:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

可以通过cat /proc/zoneinfo来查看NodeZONE计数信息:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

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_MOVABLEZONE_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函数中实现的:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

整体完成的工作也比较简单,将所有Node中可用的zone全部添加到各个Node中的zonelist中,也就是对应的struct pglist_data结构体中的struct zonelist node_zonelists字段。

这一步之后,准备工作基本就绪,进行页面申请的工作就可以开始了。

4. alloc_pages

下面的流程开始真正的页面申请了,在内部的实现中通过__alloc_pages来实现的:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

在页面分配时,有两种路径可以选择,如果在快速路径中分配成功了,则直接返回分配的页面;快速路径分配失败则选择慢速路径来进行分配。

4.1 Fast Path

快速路径分配,是通过get_page_from_freelist来完成的,具体的流程及分析如下图所示:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

4.2 Slow Path

慢速路径分配,最终也会调用get_page_from_freelist,流程分析如下:

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

【原创】(六)Linux内存管理 - zoned page frame allocator - 1

【原创】(六)Linux内存管理 - zoned page frame allocator - 1的更多相关文章

  1. 【原创】(八)Linux内存管理 - zoned page frame allocator - 3

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  2. 【原创】(七)Linux内存管理 - zoned page frame allocator - 2

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  3. 【原创】(九)Linux内存管理 - zoned page frame allocator - 4

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  4. 【原创】(十)Linux内存管理 - zoned page frame allocator - 5

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  5. Linux内存管理 (11)page引用计数

    专题:Linux内存管理专题 关键词:struct page._count._mapcount.PG_locked/PG_referenced/PG_active/PG_dirty等. Linux的内 ...

  6. 【原创】(十四)Linux内存管理之page fault处理

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  7. Linux内存管理6---伙伴算法与slab

    1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...

  8. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

  9. Linux内存描述之内存页面page–Linux内存管理(四)

    服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...

随机推荐

  1. .NET基础架构方法—DataTableToList通用方法

    p { display: block; margin: 3px 0 0 0; } --> .NET架构基础方法—DataTableToList通用方法   我们经常需要将从数据库中所读取的数据以 ...

  2. Java 动态代理作用是什么?

    Java 动态代理作用是什么?   1 条评论 分享   默认排序按时间排序 19 个回答 133赞同反对,不会显示你的姓名 Intopass 程序员,近期沉迷于动漫ING 133 人赞同 ① 首先你 ...

  3. Hyperledger fabric Client Node.js Hello World示例程序

    简介 Hyperledger fabric Client (HFC)提供了基于Node.js的应用接口来访问Hyperledger区块. 本文介绍了一个使用HFC访问IBM Bluemixr区块服务的 ...

  4. Java集合系列:-----------04fail-fast总结(通过ArrayList来说明fail-fast的原理以及解决办法)

    前面,我们已经学习了ArrayList.接下来,我们以ArrayList为例,对Iterator的fail-fast机制进行了解.内容包括::1 fail-fast简介2 fail-fast示例3 f ...

  5. Flume interceptor 使用注意事项

    1. 在使用 Regex Filtering Interceptor的时候一个属性是excludeEvents 当它的值为true 的时候,过滤掉匹配到当前正则表达式的一行 当它的值为false的时候 ...

  6. Swift-06-闭包

    看完记不住,只好继续抄课文. 如果某个存储型属性的默认值需要特别的定制或者准备,就可以使用闭包或者全局函数来为其属性提供定制的默认值.每当某个属性所属的新类型实例创建时,对应的闭包或者函数会被调用,而 ...

  7. [原创] zabbix学习之旅六:如何解决zabbix server在内网,而邮件发送服务器在外网的问题

    通过前面的文章,你已经可以快速地搭建一个报警系统,并能正常的收到报警邮件了.不过在很多企业级环境下,邮件发送服务器往往放在外网,而zabbix server放置在内网,在这种情况下,zabbix的报警 ...

  8. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(44)-工作流设计-设计表单

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(44)-工作流设计-设计表单 系列目录 设计表单是比较复杂的一步,完成一个表单的设计其实很漫长,主要分为四 ...

  9. SICP-2.2-数据的抽象

    数据的抽象 生活中有许多的事物具有复合结构,例如地理位置所用的经纬度,便是通过一个复合结构来代表位置,在我们的程序当中,我们设法将经度纬度组合成一对,我们既可以把他们当做一个整体单元来进行操作,而且也 ...

  10. 用Git的hooks实现项目的自动部署

    https://segmentfault.com/a/1190000003836345?_ea=386770 http://blog.csdn.net/wsyw126/article/details/ ...