概述:

本篇主要是对伙伴系统的页面分配器的实现进行一个梳理。在内核中伙伴系统算得上内存管理的一个基石了,毕竟页面的分配全权由它负责,即使是slab分配器也是在它的基础上进行实现的。页面分配器的函数在内核中有着各种各样的版本,不论是返回虚拟地址的还是返回struct page指针的,最终都会调用一个共同的接口:__alloc_pages_nodemask()

页面分配API:

以下是几个常见的页面分配函数,可以看到最终都会调用__alloc_pages_nodemask()

__alloc_pages_node  /*返回struct page的指针*/__alloc_pages__alloc_pages_nodemaskalloc_pages         /*返回struct page的指针*/alloc_pages_current__alloc_pages_nodemask__get_free_pages    /*返回页面的虚拟地址*/__get_free_pagesalloc_pagesalloc_pages_current__alloc_pages_nodemask

核心梳理__alloc_pages_nodemask():

上面我们看到__alloc_pages_nodemask()即页面分配器的'心脏'了,接下来我们就梳理下这颗'心脏'中都具体做了哪些事情,主要有三步:

__alloc_pages_nodemaskprepare alloc_context   //1.准备参数get_page_from_freelist  //2.快路径尝试分配内存 __alloc_pages_slowpath  //3.慢路径尝试分配内存

细节如下:

由于分配过程很复杂,会涉及到大量的判断,以及numa node和zone的选择,所以会根据用户传参、进程配置(process flags)以及系统配置(mem policy或cgroup等)去整理一些参数,通过这些参数来控制后续内存分配和内存回收的行为。

1. 参数整理:

对__alloc_pages_nodemask()中的形参进行处理,整合出三个关键变量alloc_mask、alloc_flag以及struct alloc_context。(第一次整理后参数给fasthpath使用,若fastpath分配失败,进入slowpath前还会微调这些参数)

alloc_mask:存放处理后的gfp_mask。处理主要包括:1.过滤无效的mask;2.根据是否开启cpuset添加__GFP_HARDWALL;3.若请求发生在进程中,继承任务的GFP_FS/IO的行为。alloc_flag:存放一些功能行为的mask。功能行为包括:1.cpuset是否开启;2.watermark的水位线用哪根。3.请求发生在进程中,继承任务的PF_MEMALLOC_xx的行为。alloc_context:存放了关于从哪获取pageblock的参数。参数主要包括:zonelist、nodemask和preferred_zoneref

2. 快路径(fastpath)分配:

get_page_from_freelist      //从preferred zonelist中分pagezone_watermark_fast/ok    //检测水位,具体是min low high由ALLOC_WMARK_xx决定node_reclaim            //wmark不ok,就根据回收模式判断是否进行回收rmqueue            //wmark很ok,分配pagermqueue_pcplist         //order为0时,从pcp中分配__rmqueue_smallest      //order大于0时,从free_area[]中分配

快路径总结:
(整体进入for循环,遍历尝试zonelist中的zone直至分配内存成功或失败,for循环中的处理如下)
1. 参数检查,若有不满足,直接continue跳过当前zone;
2. 检查水位zone_watermark_fast/ok。其中high low min水位线用哪根儿具体由alloc_flags中的ALLOC_WMARK_xx标志决定;
3. 若水位不ok,则根据回收模式zone_reclaim_mode的设置,判断是回收或是跳过当前zone,倘若最终没一个zone是ok的,则快路径失败,进入慢路径slowpath。
4. 若水位很ok,都符合了的话则rmqueue函数尝试分配页面,其中会区分order-0和非order-0的情况。

watermark的检测:

首先wmark_pages()会根据alloc_flags中设置的是min或low或high去算出该zone的watermark是多少;然后将该watermark传入zone_watermark_ok()判断该zone的free pages是否满足该水线。(检查过程会根据内存分配的紧急程度放宽watermark)

(详见章节: 内存回收(一):watermark与lowmem_reserve)。

核心函数rmqueue():

get_page_from_freelist()函数中做了一系列检查,都是为了最终能调用rmqueue()函数从zone中拿到合适order的内存。细看上面的框图,我们可以发现rmqeue()中根据order是否为0会分别调用rmqueue_pcplist()或__rmqueue_smallest(),原因如下:

  • order=0:

内核中将order-0的请求和大于order-0的请求在处理上做了区分。现在的处理器动不动就十几个核,而zone就那么几个,当多个核要同时访问同一个zone的时候,不免要在zone的锁的竞争上耗费大量时间。社区开发者发现系统中对order-0的请求在内核中出现的频次极高,且order-0所占内存仅一个页的大小,于是就实现了per cpu的"内存池",用来满足order-0页面的分配,这样就在一定程度上缓解了伙伴系统在zone的锁上面的竞争。

static struct page *rmqueue_pcplist(...)
{/*关闭本地中断并保存中断状态(因为中断上下文也可以分配内存)*/local_irq_save(flags);/*获取当前CPU上目标zone中的per_cpu_pages指针*/pcp = &this_cpu_ptr(zone->pageset)->pcp;/*获取per_cpu_pages中制定迁移类型的页面list*/list = &pcp->lists[migratetype];/*从链表上摘取目标页面*/page = __rmqueue_pcplist(zone,  migratetype, alloc_flags, pcp, list);/*若分配成功,更新当前zone的统计信息*/if (page) {__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);zone_statistics(preferred_zone, zone);}/*恢复中断*/local_irq_restore(flags);return page;
}

  • order>0:

在__rmqueue_smallest()中从小到大循环遍历各个order的free_list链表,直到使用get_page_from_free_area()成功从链表上摘取到最小且合适(order和migratetype都合适)的pageblock

__rmqueue_smallest()get_page_from_free_area()

3. 慢路径(slowpath)分配

__alloc_pages_slowpathwake_all_kswapds              //首先唤醒所有kswapd线程,并确保slowpath过程中一直是醒着的get_page_from_freelist        //调整一下alloc_flags,尝试分配get_page_from_freelist        //调整一下alloc_flags和zonelist,再试下分配__alloc_pages_direct_reclaim  //reclaim后再尝试分配,属于同步回收__alloc_pages_direct_compact  //compact后再尝试分配,属于同步回收__alloc_pages_may_oom         //反复尝试reclaim和compact后仍不成功,则oom杀进程后再尝试分配,属于同步回收

慢路径总结:

快路径(fastpath)检查了各个zone的low watermark,若所有zone的内存水位线都低于low,则失败并进入慢路径(slowpath)。

1. 慢路径第一件事就是先唤醒所有的kswapd内核线程展开异步回收。(异步回收)
2. 由于在进入慢路径时会对alloc_flags进行调整,且已经开启了异步回收,再次尝试分配或许会成功。
3. 再次调整alloc_flags以及zonelist后尝试分配或许会成功。
4. 调用__alloc_pages_direct_reclaim(),其中会先进行直接内存回收,然后尝试分配内存。(同步回收)
5. 调用__alloc_pages_direct_compact(),其中会进行内存压缩(或内存规整),扫描free_area[]对碎片化的内存进行整理,然后尝试分配内存。(同步回收)
6. 调用__alloc_pages_may_oom()触发OOM,杀掉得分最高的进程,然后尝试分配内存。(同步回收)
7. 整个过程会根据实际情况可能循环尝试3、4、5三个步骤,或循环尝试3、4、5、6四个步骤。

4. slowpath中的各种回收机制

下面梳理了slowpath中四种回收机制的调用关系,细节待补充。

4.1 slowpath中的kswapd(异步回收)

创建kswapd: kernel启动时会调用kswapd_init()为每个NUMA node都创建一个kswapd内核线程。

kswapd_initkswapd_runkthread_run(kswapd, ..)

唤醒kswapd: __alloc_pages_nodemask()分配过程中,当watermark低于low时会唤醒kswapd进行异步回收。

wake_all_kswapdswakeup_kswapd

4.2 slowpath中的reclaim(同步回收)

__alloc_pages_direct_reclaim__perform_reclaimtry_to_free_pagesdo_try_to_free_pagesshrink_zonesget_page_from_freelist

4.3 slowpath中的compact(同步回收)

__alloc_pages_direct_reclaim__perform_reclaimtry_to_free_pagesdo_try_to_free_pagesshrink_zonesget_page_from_freelist

4.4 slowpath中的OOM(同步回收)

__alloc_pages_may_oomout_of_memoryoom_kill_process

原创文章,转载和引用请注明出处。

作者:Yann Xu

autojs遍历当前页面所有控件_伙伴系统:页面分配器相关推荐

  1. autojs遍历当前页面所有控件_自定义控件(引入布局)

    系统给我们提供了许多功能强大的控件,我们在需要时可以直接在布局中添加使用,但是有时候我们程序想要实现的功能往往因人而异,如:我们的程序需要在内个Activity的标题栏左侧有一个返回按钮(类似于iPh ...

  2. autojs遍历当前页面所有控件_纯前端表格控件SpreadJS V14.0发布:组件化编辑器+数据透视表 - 葡萄城开发工具...

    SpreadJS 是一款基于 HTML5 的纯前端表格控件,兼容 450 种以上的 Excel 公式,具备"高性能.跨平台.与 Excel 高度兼容"的产品特性,可为用户提供高度类 ...

  3. autojs遍历当前页面所有控件_树形控件在生产力工具中的设计

    惊!半年实践血泪史,3000 字深度好文,一个爱树的设计师手把手教你如何设计「树 」! 树形控件是种常见的设计模式,几乎与图形化用户界面同时诞生,通过结构化的组织方式逐级展示内容,让整体信息架构一目了 ...

  4. Xamarin自定义布局系列——PivotPage(多页面切换控件)

    原文:Xamarin自定义布局系列--PivotPage(多页面切换控件) PivotPage ---- 多页面切换控件 PivotPage是一个多页面切换控件,类似安卓中的ViewPager和UWP ...

  5. 第三篇:属性_第二节:控件属性在页面及源码中的表示方式

    一.属性在页面及源码中的表示方式 认真地看看页面中声明控件的代码,你会发现控件属性在页面中的表示千变万化.我们看看下面这些: <%@ Page Language="C#" A ...

  6. 怎么把一个控件放到tab页面上去?_移动端页面内容切换

    # 移动端页面内容切换 上周做了一个和页面切换相关的需求,为了探寻在需求场景下最符合用户心理模型的交互方式,当时一共输出了有四五种方案.总结一下各种切换页面内容的方式的特点和他们适用的场景.## 一. ...

  7. 如何在用户控件中操作页面中的控件?

    一般来讲我们会把功能集中在ASCX文件实现,以便能够多次使用,但在某种情况下,我们可能会用到对用户控件所在的页面容器进行操作. 其实如果想一下,道理也很简单,如果ASCX被使用了,其会出现在页面容器中 ...

  8. C# webbrowser控件点击页面按钮

    用金山快盘时需要每天签到挣空间容量,一直都想写个定时程序实现,然后挂到实验室的服务器上.通过参考网上一些资料,自己动手实现一个利用webbrowser控件实现了自动点击网页按钮的功能,其实很简单的,下 ...

  9. 用户控件如何控制ASPX页面的控件

    问题来自论坛http://topic.csdn.net/u/20120415/17/3f264265-b25c-4db8-a192-520e8a60e4c1.html?85396 问题分析,aspx页 ...

  10. 巧用Delegate在Silverlight多个页面、控件中传递回调方法

    在论坛中看到经常有人碰到如何在SilverLight多个页面或者控件中传替参数或者值的问题,今天抽空通过Delegate机制实现回调实例方法重设动画参数的DEMO,分享给大家.最终结果如图: 在论坛中 ...

最新文章

  1. jersey rest webservice
  2. System memory 466092032 must be at least
  3. 020.day20 线程概述 多线程优缺点 线程的创建 线程常用方法 生命周期 多线程同步...
  4. IBM T61 键盘没有反映。
  5. 只需四步完成java JDK1.8的下载安装与配置【图文详解】
  6. 简单高效地控制高亮度LED
  7. 转:C++中STL用法总结
  8. 安装python缺少dll_解决win7操作系统Python3.7.1安装后启动提示缺少.dll文件问题
  9. java applet插件下载_Java Applet.zip
  10. 【CV2】Python中cv2使用小窗口显示高分辨率图片
  11. 10个妙招 在线视频下载方法大全
  12. 经纬度5位数和6位数差多少_经度和纬度的最大长度是多少?
  13. 数据评估:SD(标准差), 方差, 方差分析(ANOVA)
  14. linux虚拟内存设置为多少合适,虚拟内存怎么设置最好_虚拟内存设置多少合适
  15. oracle 定时 analyze,Oracle工具:Analyze
  16. IBM“移动优先”官网正式上线:苹果静候佳音
  17. 攻防世界(练习小题)
  18. 猿创征文|后端开发工程师提升开发效率神器推荐
  19. Springboot 2.0.x Redis缓存Key生成器,自定义生成器
  20. 高新技术企业避坑解读之“盲目跟风”

热门文章

  1. python --通过urlretrieve下载MP4文件
  2. 产品初探:银行理财产品简介
  3. 小学校本课程计算机前言,《创意手工》三河小学校本课程——序言
  4. 免费的查询IP归属地接口分享
  5. [导入]北京地区铁路客票代售点列表
  6. Java之批量分卷压缩与解压缩实现
  7. 迪拜政府和当地银行合作推出基于区块链的贷款平台
  8. mysql 1236错误_mysql故障~Got fatal error 1236 解决方法
  9. EPIC的服务器稳定吗,epic国内有服务器吗(epic服务器在哪)
  10. 菜哥学知识图谱(通过“基于医疗知识图谱的问答系统”)(三)(代码分析)