关于Meminfo中MemAvailable 理解
关于Meminfo中MemAvailable 理解
我们知道linux提供了proc文件系统可以给用户查看一些系统信息,其中与内存相关的文件包含如下:
- /proc/meminfo
- /proc/zoneinfo
- /proc/vmstat
- /proc/buddyinfo
- /proc/sys/vm/
上述这些内容就是我们在遇到一些压测类问题时常看的内容,本部分内容介绍对于meminfo中的MemAvailable字段的理解;
本文主要介绍如下内容:
- MemAvailable计算过程中相关的概念理解说明,包含managed_pages、min_free_kbytes、watermark等
- MemAvailable的计算过程;
- 系统提供了哪些文件接口可以调整其大小?
1. MemAvailable 的用处
首先来看meminfo中的内容:
我们主要会关注三个主要指标:total、free和available:
- MemTotal 用于描述受kernel管理的所有内存项;
- MemFree 用于描述系统中处于Free状态的内存项;
- MemAvailable 用于描述系统中可供分配的内存项,注意这一项是一个估测值,其中包含Free和可回收的一部分内存项;
一般来说我们认为available项还有空间的话说明系统还处于一个正常状态,那么Avialable这一项是怎样算出来的呢?
2. MemAvailable的计算
我们先回答第一个问题,即Available这一项是如何计算出来的,直接上code:
available = si_mem_available(); //计算获取到available
...
show_val_kb(m, "MemAvailable: ", available); //将其显示出来//具体来看 si_mem_available()的实现:/mm/page_alloc.c
long si_mem_available(void)
{long available;unsigned long pagecache;unsigned long wmark_low = 0;unsigned long pages[NR_LRU_LISTS];struct zone *zone;int lru;for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)pages[lru] = global_node_page_state(NR_LRU_BASE + lru);for_each_zone(zone)wmark_low += zone->watermark[WMARK_LOW];//遍历zonelist获取每个zone的watermark值available = global_page_state(NR_FREE_PAGES) - totalreserve_pages;//free - reserve//注意这里reserve指的是各个zone中的lowmem部分和watermark[high]部分//接下来计算pagecache中可回收的部分,这里回收FILE部分而未计算anoy部分是基于处理效率的考虑,anoy部分需要swap申请buffer以及emmc空间写入,而file只需要discard或者writeback即可;pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];pagecache -= min(pagecache / 2, wmark_low);//取一半和wmark_low中较小的那个去除;available += pagecache;//接下来计算slab分配器分配内容中可回收的部分available += global_page_state(NR_SLAB_RECLAIMABLE) - min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);if (available < 0)available = 0;return available;
}
上述code中的注释和图示已经将上述逻辑做了说明,即available是free的内存项中去除维持系统运行所必须的部分再加上可回收部分;
计算过程中实际引入了totalreserve_pages、watermark等几个字段,接下来依次介绍其含义:
2.1 totalreserve_pages 理解
上述计算中,我们首先用free的内存项去除了reserve的部分,这个reserve部分表示系统运行所必须的部分,主要包含lowmem和watermark部分:
整体计算即如上述图示说明,即各个zone中的managed / ratio 累加后再叠加上watermark所必备的部分即reserve部分;
//totalreserve_pages定义在:/include/linux/mmzone.h 是pglist_data的成员
/** calculate_totalreserve_pages - called when sysctl_lowmem_reserve_ratio* or min_free_kbytes changes.*/
static void calculate_totalreserve_pages(void)
{struct pglist_data *pgdat;unsigned long reserve_pages = 0;enum zone_type i, j;for_each_online_pgdat(pgdat) {//对所有的node进行遍历,嵌入式设备只有一个nodepgdat->totalreserve_pages = 0;for (i = 0; i < MAX_NR_ZONES; i++) {//对所有zone进行遍历,如无特别处理则有:DMA \ Normal \ HighMem 三个zonestruct zone *zone = pgdat->node_zones + i;long max = 0;for (j = i; j < MAX_NR_ZONES; j++) {//取zone中lowmem_reserve最大的那个if (zone->lowmem_reserve[j] > max)max = zone->lowmem_reserve[j];}max += high_wmark_pages(zone);if (max > zone->managed_pages)//判断如果max数值超过了kernel对应zone中管理的pages,则标记为managed_pagesmax = zone->managed_pages;//如无bug,这里应该很难进的来;pgdat->totalreserve_pages += max;reserve_pages += max;//对于我们的板子来说,这两个值是一样的;}}totalreserve_pages = reserve_pages;
}
//经过上述计算过程,lowmem_reserve和managed_pages这两个变量需要确认其计算过程
/** setup_per_zone_lowmem_reserve - called whenever* sysctl_lowmem_reserve_ratio changes. Ensures that each zone* has a correct pages reserved value, so an adequate number of* pages are left in the zone after a successful __alloc_pages().*/
static void setup_per_zone_lowmem_reserve(void)
{struct pglist_data *pgdat;enum zone_type j, idx;for_each_online_pgdat(pgdat) {//遍历所有nodefor (j = 0; j < MAX_NR_ZONES; j++) {//遍历所有zone,都是一样的套路,目的就是计算出来每个zone的数值struct zone *zone = pgdat->node_zones + j;unsigned long managed_pages = zone->managed_pages;//从zone中获取到managed_pageszone->lowmem_reserve[j] = 0;idx = j;while (idx) {struct zone *lower_zone;idx--;if (sysctl_lowmem_reserve_ratio[idx] < 1)//获取到这个系数,默认配置为256 32 32sysctl_lowmem_reserve_ratio[idx] = 1;lower_zone = pgdat->node_zones + idx;lower_zone->lowmem_reserve[j] = managed_pages / sysctl_lowmem_reserve_ratio[idx];//managed / 系数managed_pages += lower_zone->managed_pages;}}}/* update totalreserve_pages */calculate_totalreserve_pages();
// free_area_init_core 接口中描述了managed_page的初始化过程,zoneinfo中可以看到其数值,zone结构体中可以看到其定义
//这里没有将managed_pages计算的部分列出来,后续有机会再补充
}
2.2 watermark 理解
直接来看图示:
watermark的计算相较于reservedmem来说要复杂一些,主要包含:
- 计算min_free_kbytes,此数据是根据managed_pages计算出来的,可以通过proc文件系统修改配置;
- 计算watermark,简单来说就是将min_free_kbyte按照比例划分给各个zone,就是watermark[WMRK_MIN];
详细来看code:
static void __setup_per_zone_wmarks(void)
{unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);//将min_free_kbytes转换为pagesunsigned long lowmem_pages = 0;struct zone *zone;unsigned long flags;for_each_zone(zone) {if (!is_highmem(zone))lowmem_pages += zone->managed_pages;//计算出所有lowmem_pages有多少;}for_each_zone(zone) {u64 tmp;spin_lock_irqsave(&zone->lock, flags);tmp = (u64)pages_min * zone->managed_pages;do_div(tmp, lowmem_pages);//这两步计算就是按照比例划分lowmem而已if (is_highmem(zone)) {//对于highzone部分有些差别,他不是lowmem,所以这里计算出来的是额外地;unsigned long min_pages;min_pages = zone->managed_pages / 1024; //处理也是很简单,直接 / 1024min_pages = clamp(min_pages, SWAP_CLUSTER_MAX, 128UL);//确保在范围内,128~64M吧zone->watermark[WMARK_MIN] = min_pages;} else {zone->watermark[WMARK_MIN] = tmp;}tmp = max_t(u64, tmp >> 2, mult_frac(zone->managed_pages, watermark_scale_factor, 10000));//这里是做个比较,tmp /4 和 managed_page * factor / 10000的大小,默认情况下这里是/1000,tmp较大;zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + tmp;zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2;spin_unlock_irqrestore(&zone->lock, flags);}calculate_totalreserve_pages();
}/** Initialise min_free_kbytes.** For small machines we want it small (128k min). For large machines* we want it large (64MB max). But it is not linear, because network* bandwidth does not increase linearly with machine size. We use** min_free_kbytes = 4 * sqrt(lowmem_kbytes), for better accuracy:* min_free_kbytes = sqrt(lowmem_kbytes * 16)** which yields** 16MB: 512k* 32MB: 724k* 64MB: 1024k* 128MB: 1448k* 256MB: 2048k* 512MB: 2896k* 1024MB: 4096k* 2048MB: 5792k* 4096MB: 8192k* 8192MB: 11584k* 16384MB: 16384k*/
int __meminit init_per_zone_wmark_min(void)
{unsigned long lowmem_kbytes;int new_min_free_kbytes;lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10);//将获取到的page转换为kbytesnew_min_free_kbytes = int_sqrt(lowmem_kbytes * 16);//这个计算就很简单了,上述注释也有说明;if (new_min_free_kbytes > user_min_free_kbytes) {min_free_kbytes = new_min_free_kbytes;if (min_free_kbytes < 128)//最小128kbytesmin_free_kbytes = 128;if (min_free_kbytes > 65536)min_free_kbytes = 65536;//最大65536Kbytes} else {pr_warn("min_free_kbytes is not updated to %d because user defined value %d is preferred\n",new_min_free_kbytes, user_min_free_kbytes);}setup_per_zone_wmarks();refresh_zone_stat_thresholds();setup_per_zone_lowmem_reserve();return 0;
}
core_initcall(init_per_zone_wmark_min)
整个计算的过程还是蛮简单的,理解起来也不复杂;
另外说明下这个watermark是用来干啥的:
字段 | 说明 |
---|---|
zone->watermark[WMARK_MIN] | 低于min说明内存已经非常紧张了,需要kswap线程持续回收内存,并且在申请时会直接释放后分配 |
zone->watermark[WMARK_LOW] | 低于low说明此时内存已经比较紧张,需要唤醒swap进行释放直至到达high |
zone->watermark[WMARK_HIGH] | 高于high说明此时内存比较健康 |
3. 如何改变MemAvailable的值
根据前文的计算我们可以知道,MemAvailable表示系统中包含可回收的内存总共有多少可以被分配的Mem;
其依赖于reserveMem 和 watermark:
- 修改 sysctl_lowmem_reserve_ratio 可以改变reservemem的大小,即减小系数可以增加reserve;
- 修改 min_free_kbyte可以改变watermark的大小;
- 修改 watermark_scale_factor会改变watermark[low & high]的大小,进而影响到reserve的大小;
通过修改上述即可字段即可以改变到计算出来的available的大小,不过貌似也只是改变了触发回收mem的时机,没有太多的作用的样子;
4. meminfo中其他字段
5. 附录
相关涉及文件目录:
目录 | 说明 |
---|---|
/fs/proc/meminfo.c | meminfo的入口 |
/mm/page_alloc.c | si_mem_available等相关计算实现文件 |
/include/linux/mmzone.h | totalreserve_pages定义 |
这几天跟踪了这部分code,顺便将其简单整理了出来,写的没什么逻辑
关于Meminfo中MemAvailable 理解相关推荐
- 在实践中深入理解IP协议
本文为我个人计划撰写的博客专题<在实践中深入理解常见网络协议>中关于IP协议的一篇,有兴趣的朋友可以继续关注我的博客,我将会陆续撰写各种协议的实践分析文章. TCP/IP协议栈其实当然不止 ...
- 博客专题计划:《在实践中深入理解常见网络协议》
为什么要写这个系列的技术博文: 距离学习CCIE的课程已经有近一年的时间,虽然这一年来已经丢下了挺多关于路由交换技术的知识,不过随着这一年时间以来通过对Linux和Python的学习研究和学校相关课程 ...
- 干货!任务型对话中语言理解的鲁棒性测试
|清华刘劼西
点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 本期AI TIME PhD直播间,我们邀请到了清华大学计算机科学与技术系的硕士生--刘劼西,带来分享--<任务型对话中语言理解的鲁 ...
- IOC在墨者革离中的理解
IOC在墨者革离中的理解 实现墨者革离场景 首先是实现MoAttack public class MoAttack{public void cityGateAsk(){//让演员进场LiuDeHua ...
- Android 设计模式之MVC,从一个实例中来理解MVC
前言 已经有几天没有写过帖子了,主要前一段时间在忙公司的项目,现在闲下来想看一下其他的东西,然后从公司的iOS大神那里了解到了苹果的设计模式是MVC,于是想着自己也来写一下Android这边的MVC. ...
- 智能催收系统中自然语言理解模块设计
摘要 随着社会信贷消费的流行,待催收的违约用户逐渐增多.针对此问题,对Rasa对话系统开发框架中的自然语言理解模块进行改进,显著提升智能催收系统中自然语言理解模块的准确率,并对最终得到的训练模型进行性 ...
- 体素坐标(voxel_coors)在mmdetection3d中的理解
体素坐标(voxel_coors)在mmdetection3d中的理解 针对KITTI数据集举例. 1. 范围说明 point_cloud_range [0, - 40, -3, 70.4, 40, ...
- 在python中、对于函数定义代码的理解_python中如何理解装饰器代码?
长文预警,[最浅显易懂的装饰器讲解] 能不能专业地复制题目?配上代码,问题分段. 我来给提主配上问题的代码. 正式回答: 1:如何理解return一个函数,它与return一个值得用法区别在哪? 敲黑 ...
- ARP-地址解析协议(在实践中深入理解ARP协议)
在同一个网络(无特别说明,均指以太网络)中进行通信的主机,必须要拥有目标主机的MAC地址才能够正确地将数据发送给目标主机,那么如何知道目标主机的MAC地址呢?可以通过ARP协议.ARP协议就是用来获取 ...
- oracle中@,深入理解Oracle中的DBCA
但凡是学习 过Oracle的同学,DBCA都是一个必备工具,有了这个工具,创建数据库成为可能.而DBCA本身有图形和静默两种方式.静默方式看起来高大上,可以轻松搞定一个看似很复杂的创建数据库过程,而只 ...
最新文章
- 【tensorflow】OP_REQUIRES failed at variable_ops.cc:104 Already exists: Resource
- 文本比较算法Ⅴ——回顾贴,对前面几篇文章的回顾与质疑
- Jzoj4209 已经没有什么好害怕的了
- 实现tree系统命令
- extjs设计器破解程序及开发调试工具
- 设计模式之-简单工厂模式
- 1027. 打印沙漏(20)-PAT乙级真题
- java exception 包_什么是Java中的异常包装?
- HDMI 分配器正确使用方法
- 广义速度V与管理理论——流水线、TPS…
- 吃桃子削不削皮 如何吃有保证
- 数学模型 Lotka-Volterra
- 有没有java自编歌曲_简易音乐播放器制作
- 如何让iPad浏览器不再拒绝访问请求
- 蓝牙热敏打印开发(佳博打印机)
- PL/SQL教程:PL/SQL Developer使用技巧
- “北美之鹰”试图借助Windows 10物联网核心版打破世界陆地速度记录
- 【转】张飞眼中的真实三国-爆笑日记
- React路由跳转时通过传参进行动态渲染的方法
- Linux expr 命令详解
热门文章
- webpack@3.6.0(4) -- 配置模块化开发
- Thread.Join 和 Task.Wait 方法
- Coded UI Test学习网站
- 【Struts1】--beanutils
- 使用IronPython集成Python和.NET
- 【玩转Ubuntu】02. Ubuntu上搭建Android开发环境
- 如何将SL的image保存到SL的独立存储文件系统
- matlab实现epirb调制,[单选] 根据《建筑安装工程费用项目组成》(建标[2003]206号)的规定,下列属于直接工程费中材料费的是()。...
- centos7 安装mysql_第02期:ClickHouse 单机部署以及从 MySQL 增量同步数据
- Java-web下使用RSA进行加密解密操作