linux 内存回收mglru算法代码注释2

mglru与原lru算法的兼容

旧的lru算法有active与inactive两代lru,可参考linux 内存回收代码注释(未实现多代lru版本)-CSDN博客

新的算法在引入4代lru的同时,还引入了tier的概念。

新旧算法的切换的实现在lru_gen_change_state,当开启mglru时,调用fill_evictable,将active list 与 inactive list 的folio迁移到 mglru上(mglru的组织方式是:lruvec[gen][type][zone]),如果是关闭mglru,则调用drain_evictable,将mglru的folio迁移回active/inactive list两代的情况。

当开启mglru时,原有shrink_node与shrink_lruvec的路径会短路,主要体现在两个地方,对于全局的回收直接调用lru_gen_shrink_node,对于某个memory group 的回收会间接调用lru_gen_shrink_lruvec:

shrink_nodeif (lru_gen_enabled() && root_reclaim(sc)) {lru_gen_shrink_node(pgdat, sc);return;}shrink_lruvecif (lru_gen_enabled() && !root_reclaim(sc)) {lru_gen_shrink_lruvec(lruvec, sc);return;}

真正做页的回收的逻辑还是在shrink_folio_list。 

mglru与原lru算法的差别

与旧的lru算法区别,主要有三个方面:1、修改了一次扫描要扫的数量计算逻辑。2、修改了代与代之间转换的逻辑。3、添加了refault页的延迟回收机制

mglru的组织

每个numa node 有一个 pgdat 结构,上面绑定了为每个memory group准备了两代bin list,分别为young bin list和old bin list,第个bin list 上有8个bin,新加入的memory group会随机找一个 bin list 加入(lru_gen_online_memcg)。回收总是在old代上做,找一个bin list,从头扫描到尾。memory group 会随着它分配的内存大小和是否做了回收,在old与young的bin list 头尾上游走。(lru_gen_rotate_memcg),具体而言:

1、memory group 的内存超过 soft limit 时,将它移至同代的开头,下次可能回收它(lru_gen_soft_reclaim,MEMCG_LRU_HEAD)

2、新加入的memory group会放在新代的结尾处,第一次扫描发现页数少于2^priority或是第一次扫描发现页数在low水位线以下时,会放在新代的结尾处(MEMCG_LRU_TAIL)

3、当第一次扫描发现内存在min水位以下,或第二次扫描发现上次扫描是小于2^priority的,或是每次扫描完足够页数时会把最后一个扫描的memory group 移至新代(MEMCG_LRU_YOUNG)。

4、在移除一个memory group时,需要回收全部内存,会把它放在old代(lru_gen_offline_memcg,MEMCG_LRU_OLD)

bin list 中每一项是memory group的lruvec指针。

lruvec内部分成了4代,每代有两个type:文件or匿名,每个type又维护了每个zone上的页框,如下:

// 找一个 group 对应在某个 node 上的lru
lruvec = &memcg->nodeinfo[pgdat->node_id]->lruvec.lrugen;
// 遍历一个 node 上某个 binlist 的 lru 
lrugen = pgdat->memcg_lru.fifo[gen][bin];
// lru 内的页框
lrugen->folios[gen][type][zone]

扫描数量

原有的swappiness表示回收匿名页与文件页的加权,取值1~200,值越小越支持从匿名页回收。新算法计算扫描数量的方法变了,只根据swappiness有无赋值来决定要不要计算扫描匿名页的数量,文件页一定会扫描回收。计算的方式也比较粗暴:total >> sc->priority;具体计算逻辑在get_nr_to_scan->should_run_aging。

代际转换

如果在should_run_aging计算时发现最新一代的页框数已经是总页框数的一半,或第三代的页框数小于总页框数的四分之一,就触发一次代际迭换,尝试发现young 页,把它们提升至最新代。代际迭换的代码在try_to_inc_max_seq。

try_to_inc_max_seq():// 硬件不支持自动标记access flagif (!should_walk_mmu()) {iterate_mm_list_nowalk(lruvec, max_seq);return;}// 尝试扫描 hot pmd 中的 young 页。	do {is_last = iterate_mm_list(lruvec, walk, &mm);if (mm)walk_mm(lruvec, mm, walk);} while (mm);// 这一代扫描结束,更新代际if (is_last)inc_max_seq(lruvec, can_swap, force_scan);

如果硬件支持自动在页表记录访问标记,则扫描一遍(扫描的实现在try_to_inc_max_seq->walk_mm->walk_pgd_range->walk_pud_range->walk_pmd_range->walk_pte_range),通过检查bloom filter,找到标记为hot的pmd,访问pmd中全部pte,将标记脏的pte对应页框标记为脏,并更新至最新代。这里说的bloom filter标记了平均每个cacheline中young页数大于1的pmd,只需要对这些pmd的全部pte中young 页的扫描,并标记脏和更新代数,因为这个pmd范围的young页多,是个热点区,意味着后面可能还会产生hot页。如果硬件不支持自动设置访问标记,就不能在这个地方扫了,而要等到建立rmap时,folio_referenced_one->lru_gen_look_around

bloom filter的设置有两个途径,一个是在上面说的扫描全部pte之后,计算young页数/total页数大于cacheline中能装下的pte数(或者说是不是平均每个cacheline都有一个pte项对应了young页,实现在suitable_to_scan);另一个是在shrink_folio_list时,会找一个页框映射的次数(folio_referenced),会调一次lru_gen_look_around,尝试看下这个pte对应的pmd中全部pte,同样是在标记完脏页、统计完young页数时,计算young页数/total页数大于cacheline中能装下的pte数,并把young 标记清掉。

这个过程大概代码如下:


walk_pmd_range():
{
restart:for pmd_i in start_addr.. end_addr:// 检查是不是hot pmdif (!test_bloom_filter(max_seq, pmd_i))continue;// 检查hot pmd的所有pte中的脏页,并统计young的页数和清空young标记(young 指最近有访问),计算它还是不是hot pmdis_still_hot = walk_pte_range(addr, pmd_end_addr);// 如果是hot的pmd,则在bloom filter 标记一下,下一轮(代)扫描时再检查一次这个pmdif (is_still_hot)update_bloom_filter(max_seq + 1, pmd + i);}if (i < PTRS_PER_PMD && get_next_vma(PUD_MASK, PMD_SIZE, args, &start, &end))goto restart;
}walk_pte_range():new_gen = lru_gen_from_seq(walk->max_seq);
restart:for pte_i in start_addr.. end_addr:           {// 硬件标记pte脏的,但页框没有标记脏,且这是文件页或未换出的匿名页,则在页框上标记下脏if (pte_dirty(ptent) && !folio_test_dirty(folio) &&!(folio_test_anon(folio) && folio_test_swapbacked(folio) &&!folio_test_swapcache(folio)))folio_mark_dirty(folio);// 将这一页框更新到最新代old_gen = folio_update_gen(folio, new_gen);// 更新统计walk->nr_pages[old_gen][type][zone] 和 walk->nr_pages[new_gen][type][zone]if (old_gen >= 0 && old_gen != new_gen)update_batch_size(walk, folio, old_gen, new_gen);}if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end))goto restart;// 计算young页数/total页数大于cacheline中能装下的pte数(或者说是不是平均每个cacheline都有一个pte项对应了young页)return suitable_to_scan(total, young);
}

Refault页的延迟回收

refault指缺页读入后又换出又读入。mglru引入tier概念,组织形式为lrugen->refaulted[hist][type][tier]。为file 和anon类型的页,维护了4代统计直方图(hist),每个直方图中有4个范围(tier),分别统计了本轮回收中访问了1次,2次,4次,8次的页数。

当触发refault时,会统计累加本轮回收中,已经refault这么多次的页数。(lru_gen_refault)

lru_gen_refault():// recent 指refault与上次回收在同一代内recent = lru_gen_test_recent(shadow, type, &lruvec, &token, &workingset);// 总共有4代histogram,根据当前代数算出它在那个histogram中hist = lru_hist_from_seq(READ_ONCE(lrugen->min_seq[type]));// 每代有4个tier,tier的index = log2(本轮扫描中这页的 access 数),即分别为访问1次,2次,4次,8次的tier。tier = lru_tier_from_refs(refs);// 统计累加本轮扫描过程中发生 2^tier 次 refault 的页数。atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]);

在决定是否回收页时,evict_folios->isolate_folios,会平衡本轮发生refault 的页数与回收+延时回收页数的比值,计算一个控制值(refaulted/(evicted+protected)),可以理解为发生refault的频繁程度。如果发生n次refault的频繁程度达到了发生1次refault频繁程度的2倍,则发生n次以上refault的页都不再回收。

isolate_folios():// 计算refault次数超过多少后不再释放tier_idx = get_tier_idx(lruvec, type);isolate_folios->scan_folios->sort_folio():// 本轮扫描中 refault 次数超过2^tier_idx 次的页不再释放,而是推到下一代if (tier > tier_idx) {// 将页放在下一次lru尾(回收是从本代的头开始的)gen = folio_inc_gen(lruvec, folio, false);list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]);// 累加本代中不释放页的页数int hist = lru_hist_from_seq(lrugen->min_seq[type]);WRITE_ONCE(lrugen->protected[hist][type][tier - 1],lrugen->protected[hist][type][tier - 1] + delta);return true;}

在回收过程中,每完成一次分离出回收页的计算后(isolate_folios),会将这一代的统计值更新为新值与历史值的滑动平均值。

在一轮回收结束时,会调inc_max_seq将下一轮回收的代统计值清空,为最新代的统计留出位置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/166312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ELK企业级日志分析平台——elasticsearch

集群部署 文档&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/7.6/index.html 下载&#xff1a;https://elasticsearch.cn/download/ 主机 ip 角色 k8s1 192.168.92.11 cerebro elk1 192.168.92.31 elasticsearch elk2 192.168.92.32 elasti…

数据库实验五 数据库设计

数据库实验五 数据库设计 一、实验目的二、实验内容三、实验内容四、验证性实验五、设计性实验 一、实验目的 1.了解E-R图构成要素以及各要素图元。 2.掌握概念模型E-R图的绘制方法。 3.掌握概念模型向逻辑模型的转换原则和步骤。 4.运用sql编程实现 二、实验内容 1.选取一个…

线段树---数据结构学习

线段树的教程可以参照线段树 这里推荐 https://oi-wiki.org/ 这个网站&#xff0c;数据结构讲的非常透。 线段树学了很多次忘了很多次&#xff0c;这次打算记录一下以后方便回顾(leetcode这类题遇见的不算特别多)。 样板例题 leltcode-307 #题目样板 class NumArray {private …

医院手术麻醉信息系统全套源码,自主版权,支持二次开发

医院手术麻醉信息系统全套商业源码&#xff0c;自主版权&#xff0c;支持二次开发 手术麻醉信息系统是HIS产品的中的一个组成部分&#xff0c;主要应用于医院的麻醉科&#xff0c;属于电子病历类产品。医院麻醉监护的功能覆盖整个手术与麻醉的全过程&#xff0c;包括手术申请与…

人工智能中的文本分类:技术突破与实战指导

在本文中&#xff0c;我们全面探讨了文本分类技术的发展历程、基本原理、关键技术、深度学习的应用&#xff0c;以及从RNN到Transformer的技术演进。文章详细介绍了各种模型的原理和实战应用&#xff0c;旨在提供对文本分类技术深入理解的全面视角。 关注TechLead&#xff0c;分…

Hadoop发行版 Cloudera CDH 6.3.2及CM 安装包下载(阿里云盘 不限速)

CDH&#xff08;全称Cloudera’s Distribution, including Apache Hadoop&#xff09;是由Cloudera公司构建的Hadoop稳定发行版&#xff0c;不仅含有 Apache Hadoop&#xff0c;还整合了Hive、Spark等组件。 由于CDH已停止维护&#xff0c;且Cloudera不再为CDH提供免费的下载服…

git 使用过程错误集合

文章目录 1、git-credential-manager-core was renamed to git-credential-manager2、credential-manager-core is not a git command. See git --help. 1、git-credential-manager-core was renamed to git-credential-manager 出现以下提示建议尽快更新您的 Git 配置以使用新…

回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测

回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测 目录 回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现SCN随机配置网络多变量回归预测 1.data为数据集&#xff0c;7个输入特征&#xff0…

基于Python实现汽车销售数据可视化+预测【500010086.1】

导入模块 import numpy as np import pandas as pd from pylab import mpl import plotly.express as px import matplotlib.pyplot as plt import seaborn as sns设置全局字体 plt.rcParams[font.sans-serif][kaiti]获取数据 total_sales_df pd.read_excel(r"./data/中…

独孤思维:看了那么多课程,还在问怎么赚钱的都是废物

你扪心自问&#xff1a; 为什么自己看了那么多赚钱项目&#xff0c;买了那么多课程&#xff0c;对标了那么多大咖&#xff0c;依旧赚不到钱&#xff1f; 是自己智商欠缺吗&#xff0c;是自己能力不行吗&#xff0c;是自己没有时间吗&#xff1f; 智商欠缺&#xff0c;没有谁…

机器学习第13天:模型性能评估指标

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 文章目录 交叉验证 保留交叉验证 k-折交叉验证 留一交叉验证 混淆矩阵 精度与召回率 介绍 精度 召回率 区别 使用代码 偏差与方差 介绍 区…

zerotier 搭建 moon中转服务器 及 自建planet

搭建moon 服务器 环境准备 # 安装依赖 yum install wget gcc gcc-c git -y yum install json-devel -y# 下载及安装 curl -s https://install.zerotier.com/ | sudo bash节点ID 配置 配置moon.json文件 cd /var/lib/zerotier-one/# 导出依赖 zerotier-idtool initmoon ide…

SpringBoot项目连接,有Kerberos认证的Kafka

在连接Kerberos认证kafka之前&#xff0c;需要了解Kerberos协议 二、什么是Kerberos协议 Kerberos是一种计算机网络认证协议 &#xff0c;其设计目标是通过密钥系统为网络中通信的客户机(Client)/服务器(Server)应用程序提供严格的身份验证服务&#xff0c;确保通信双方身份的真…

Spring Boot 升级3.x 指南

Spring Boot 升级3.x 指南 1. 升级思路 先创建一个parent项目&#xff0c;打包类型为pom&#xff0c;继承自spring boot的parent项目 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId&…

历时三个月,我发布了一款外卖返钱小程序

近几年&#xff0c;推广外卖红包爆火&#xff0c;各种推广外卖红包的公众号层出不穷。于是&#xff0c;我就在想外卖红包究竟是怎么一回事。就这样&#xff0c;我带着问题开始了关于外卖红包的研究。 在研究的过程中&#xff0c;我开始了解商品联盟、推广分成、cps等一系列相关…

网络攻击当搭配什么产品比较好

网络攻击无处不在&#xff0c;当要时刻谨记 2014年&#xff0c;索尼影业受到黑客攻击&#xff0c;导致公司内部文件和电子邮件泄露。 2015年&#xff0c;美国联邦政府的办公人员信息遭到盗窃&#xff0c;影响了超过2100万人的个人信息。 2016年&#xff0c;Yahoo的3亿用户账…

java 中集合之一【map】,map循环

在Java中&#xff0c;常用的集合框架有以下几个&#xff1a; 1、List&#xff08;列表&#xff09;&#xff1a;List是有序的集合&#xff0c;允许包含重复元素。常用的实现类有ArrayList和LinkedList。ArrayList是基于动态数组实现的&#xff0c;支持快速随机访问&#xff1b;…

android之图片选择器--pictureselector

推荐一个安卓图片/视频/文件选择器。简单好用。 不多废话。直接上代码&#xff1a; 首先&#xff0c;添加依赖&#xff1a; //图片选择器api io.github.lucksiege:pictureselector:v3.11.1//图片压缩api io.github.lucksiege:compress:v3.11.1//图片裁剪api io.github.lucksie…

Springboot3+vue3从0到1开发实战项目(一)

一. 可以在本项目里面自由发挥拓展 二. 知识整合项目使用到的技术 后端开发 &#xff1a; Validation, Mybatis,Redis, Junit,SpringBoot3 &#xff0c;mysql&#xff0c;Swagger, JDK17 &#xff0c;项目部署 前端开发&#xff1a; Vue3&#xff0c;Vite&#xff0c;Router…

Java数组和集合

在Java中&#xff0c;数组和集合是两个重要的概念&#xff0c;它们用于存储和操作数据。本文将详细介绍Java中的数组和集合&#xff0c;包括它们的定义、初始化、访问和常见操作 一、数组&#xff08;Array&#xff09; 数组是一种用于存储相同类型数据的容器&#xff0c;它可…