Linux内存管理:(十)KSM内核同页合并

文章说明:

  • Linux内核版本:5.0

  • 架构:ARM64

  • 参考资料及图片来源:《奔跑吧Linux内核》

  • Linux 5.0内核源码注释仓库地址:

    zhangzihengya/LinuxSourceCode_v5.0_study (github.com)

1. KSM定义

KSM指Kemel SamePage Merging,即内核同页合并,用于合并内容相同的页面。KSM的出现是为了优化虚拟化中产生的冗余页面,因为虚拟化的实际应用中在同一台主机上会有许多相同的操作系统和应用程序,许多内存页面的内容可能是相同的,所以它们可以合并,从而释放内存供其他应用程序使用。

KSM允许合并同—个进程或不同进程之间内容相同的匿名页面,这对应用程序来说是不可见的。把这些相同的页面合并成一个只读的页面,从而释放出多余的物理页面,当应用程序需要改变页面内容时,会发生写时复制。

2. 使能KSM

KSM只会处理通过madvise系统调用显式指定的用户进程地址空间,因此用户程序想使用这个功能就必须在分配地址空间时显式地调用madvise(addr,length,MADV_MERGEABLE)。如果用户想在KSM中取消某一个用户进程地址空间的合并功能,也需要显式地调用madvise(addr,length,MADV_UNMERGEABLE)。

KSM的sysfs节点在/sys/kernel/mm/ksm/目录下,如下图所示:

在这里插入图片描述

其中主要节点的描述如表所示:

在这里插入图片描述

KSM在初始化时会创建—个名为ksmd的内核线程

static int __init ksm_init(void)
{...ksm_thread = kthread_run(ksm_scan_thread, NULL, "ksmd");...
}

程序可以显式地调用madvise系统调用把用户进程地址空间添加到KSM系统中

<madvise()->ksm_madvise()->__ksm_enter()>
int __ksm_enter(struct mm_struct *mm)
{...// 把 mm 添加到 mm_slots_hash 哈希表中insert_to_mm_slots_hash(mm, mm_slot);...// 把 mm->slot 添加到 ksm_scan.mm_slot->mm_list 链表中list_add_tail(&mm_slot->mm_list, &ksm_scan.mm_slot->mm_list);...// 设置 mm->flags 中的 MMF_VM_MERGEABLE 标识位,表示这个进程已经被添加到 KSM 系统中set_bit(MMF_VM_MERGEABLE, &mm->flags);...
}

ksm_scan_thread()是ksmd内核线程的主干,它运行ksm_do_scan()函数,扫描和合并页面

static int ksm_scan_thread(void *nothing)
{...while (!kthread_should_stop()) {...if (ksmd_should_run())// ksm_do_scan() 函数在 while 循环中尝试合并页面ksm_do_scan(ksm_thread_pages_to_scan);...}return 0;
}

2. 旧版本KSM的基本实现

Linux 4.13 内核之前KSM的实现: KSM机制下采用两棵红黑树来管理扫描的页面和已经合并的页面,第一棵红黑树称为不稳定红黑树,里面存放了还没有合并的页面。在KSM里,扫描的页面会采用rmap_item数据结构来描述。第二棵红黑树称为稳定红黑树,已经合并的页面会生成—个节点,这个节点为稳定节点。如两个页面的内容是一样的,KSM扫描并发现了它们,因此这两个页面就可以合并成一个页面。对于这个合并后的页面,会设置只读属性,其中一个页面会作为稳定的节点挂载到稳定的红黑树中之后,另外一个页面就会被释放了。但是这两个页面的map_item数据结构会被添加到稳定节点中的hlist链表,如下图所示:

在这里插入图片描述

假设有3个VMA(表示进程地址空间),VMA的大小正好是—个页面的大小,分别有3个页面映射这3个VMA。这3个页面准备通过KSM来扫描和合并,这3个页面的内容是相同的。具体步骤如下图所示:

在这里插入图片描述

rmap_item 数据结构代表一个页面:

struct rmap_item {// 所有的 rmap_item 连接成一个链表,链表头在 mm_slot.rmap_liststruct rmap_item *rmap_list;union {// 当 rmap_item 加入稳定红黑树时,它指向 VMA 的 anon_vma 数据结构struct anon_vma *anon_vma;	/* when stable */
#ifdef CONFIG_NUMA// 内存节点编号int nid;		/* when node of unstable tree */
#endif};// 指向进程内存描述符struct mm_struct *mm;// rmap_item 所跟踪的用户空间虚拟地址unsigned long address;		/* + low bits used for flags below */// 虚拟地址对应物理页面的旧校验值unsigned int oldchecksum;	/* when unstable */union {// rmap_item 加入不稳定红黑树的节点struct rb_node node;	/* when node of unstable tree */struct {		/* when listed from stable tree */// 加入稳定红黑树的节点struct stable_node *head;// hlist 节点,用于添加到稳定节点的 hlist 链表中struct hlist_node hlist;};};
};

stable_node 数据结构用于描述稳定红黑树的节点,表示一个至少由两个页面合并而成的页面:

struct stable_node {union {// 红黑树节点,用于加入稳定红黑树的节点struct rb_node node;	/* when node of stable tree */struct {		/* when listed for migration */// 当 head 等于 &migrate_nodes 时表示这是一个临时的节点,主要用于 NUMA 系统struct list_head *head;struct {// 链表节点,用于添加到链式稳定节点的 hlist 链表中struct hlist_node hlist_dup;// 链表节点,用于添加到 migrate_nodes 链表中,等待迁移到合适的内存节点的稳定红黑树中struct list_head list;};};};// 链表头,共享这个 KSM 页面的 rmap_items 都添加到这个链表中struct hlist_head hlist;union {// KSM 页面的帧号unsigned long kpfn;// 上一次垃圾回收的时间unsigned long chain_prune_time;};
#define STABLE_NODE_CHAIN -1024// 挂到 hlist 链表成员的数量,若赋值为 STABLE_NODE_CHAIN,表示是一个链式的稳定节点int rmap_hlist_len;
#ifdef CONFIG_NUMA// 内存节点编号int nid;
#endif
};

3. 新版本KSM的新特性

新版本的KSM(如Linux 5.0 内核的KSM)比Linux 4.0内核的KSM新增了两项特性:

  • 内容全是零的页面进行特殊处理
  • 对稳定的节点的hlist链表进行改造,以防止大量的相同的页面聚集在一个稳定的节点中,导致页面迁移、内存规整等机制长时间等待这个页面。

上述新特性中,第—项实现起来比较简单,系统中已经存在了系统零页,我们可以对这个系统零页预先计算检查和。若在扫描页面时发现页面的检查和等于系统零页的检查和,那么直接修改这个页面的映射关系,让其映射到系统零页,这样可以释放这个页面。

第二项的实现是限制共享页面的数量在256以内,这样遍历256个页表项的时间将会限制在毫秒级别, 不会导致系统岩机。新的解决方案扩充了稳定节点的hlist链表结构,rmap_items超过256个之 后,扩展稳定的节点为链表。每个链表的成员都是一个稳定的节点,每个稳定的节点有一个hlist 链表,这个hlist链表中可以添加新的rmap_items。另外,还需要把稳定的节点和链表的头在红黑树中做—个交换。

新版本的稳定的节点包含两个形态:

  • 传统的稳定的节点:兼容旧版本的稳定的节点格式
  • 链式稳定的节点:新版本的链式节点格式

而且它们同时存放在稳定的红黑树中,如下图所示:

在这里插入图片描述

假设现在系统产生了1000个页面,并且这1000个页面的内容都是相同的,每个页面对应不同的VMA,这些VMA的大小正好是一个页面大小。接下来观察新版本的KSM如何处理这些页面,如何创建新版本的链式稳定的节点。

合并page2:

在这里插入图片描述

当扫描到第257个页面(page256)时,不稳定的红黑树没有成员,因此可以直接把page256对应的rmap_item添加到不稳定的红黑树中。

接下来,扫描第258个页面(page257),整个过程如下图所示:

在这里插入图片描述

合并第259个页面:

在这里插入图片描述

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

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

相关文章

【C++】C++入门基础讲解(二)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 导读 接着上一篇的内容继续学习&#xff0c;今天我们需要重点学习引用。 1. 引用 在C中&#xff0c;引用是一种特殊的变量&#xff…

OpenHarmony—不支持解构赋值

规则&#xff1a;arkts-no-destruct-assignment 级别&#xff1a;错误 ArkTS不支持解构赋值。可使用其他替代方法&#xff0c;例如&#xff0c;使用临时变量。 TypeScript let [one, two] [1, 2]; // 此处需要分号 [one, two] [two, one];let head, tail [head, ...tail]…

JavaScript DOM属性和方法之attribute属性对象

在HTML的DOM中&#xff0c;attribute对象表示HTML属性。HTML属性始终属于HTML元素&#xff0c;它在DOM节点中被称为属性节点。在DOM中&#xff0c;NamedNodeMap对象表示元素属性节点的无序集合&#xff0c;我们可以通过指定的索引访问指定的属性。通过element对象的attribute属…

高阶测试开发必备技能: k8s入门!

现在稍微有点规模公司都是基于docker容器化部署技巧&#xff0c;K8s现在主流&#xff0c;应用最广的容器集群管理技术。 k8s全称kubernetes&#xff08;首字母为 k、首字母与尾字母之间有 8 个字符、尾字母为 s&#xff0c;所以简称 k8s&#xff09;&#xff0c;基于Docker容器…

【学网攻】 第(13)节 -- 动态路由(OSPF)

系列文章目录 目录 系列文章目录 文章目录 前言 一、动态路由是什么&#xff1f; 二、实验 1.引入 实验拓扑图 实验配置 实验验证 总结 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学…

linux安装docker-compose

前言 如果你的docker版本是23&#xff0c;请移步到linux安装新版docker&#xff08;23&#xff09;和docker-compose这篇博客 查看docker版本命令&#xff1a; docker --version今天安装docker-compose的时候&#xff0c;找了很多教程&#xff0c;但是本地一直报错&#xff0…

给刚上小学的侄女准备新年礼物,有什么让小朋友喜欢的玩具推荐?

给刚上小学的侄女准备新年礼物&#xff0c;我觉得也是有很多选择的。因为现在的市场上款式太多了&#xff0c;选择自己心意的适合小侄女的都是可以的。但是如果非要选益智的或是智能高科技的&#xff0c;对孩子来说既能玩耍又能在玩的同时学习到知识&#xff0c;能够开拓孩子眼…

C++面试宝典第25题:阶乘末尾零的个数

题目 给定一个整数n,返回n!(n的阶乘)结果尾数中零的个数。 示例 1: 输入:3 输出:0 解释:3! = 6,尾数中没有零。 示例 2: 输入:5 输出:1 解释:5! = 120,尾数中有1个零。 解析 这道题主要考察应聘者对于数学问题的分析和理解能力,以及在多个解决方案中,寻求最优…

[docker] 利用Dockerfile多级构建缩减镜像大小

一、nginx FROM centos:7 as build #基于centos7镜像 MAINTAINER nginx on centos7 by lxy-20240125 #注释信息 ADD nginx-1.24.0.tar.gz /opt/ #将nginx安装包传输到镜像中 RUN yum -y install pcre-devel zlib-devel gcc gcc-c make && \cd /opt/nginx-1.24.0 &…

SpringCloud-高级篇(十八)

前面我们已经实现了多级缓存架构&#xff0c;大大提高了查询商品的性能&#xff0c;缓存在提高性能的同时&#xff0c;也带来了一致性的问题&#xff0c;比如说数据库发生了修改&#xff0c;这个时候&#xff0c;如果缓存依然是旧的数据&#xff0c;两者就产生了不一致&#xf…

linux0.11源码看信号的处理流程

序 日常Linux写代码或者使用中难免会使用siganl&#xff0c;包括我们使用ctrl-c结束程序&#xff0c;使用kill命令发送信号&#xff0c;或者说程序core后操作系统向程序发送的信号&#xff0c;以及我们程序内部自定义的信号处理。 我们选择linux0.11一个原因是它比较简单&…

瑞_力扣LeetCode_二叉搜索树相关题

文章目录 说明题目 450. 删除二叉搜索树中的节点题解递归实现 题目 701. 二叉搜索树中的插入操作题解递归实现 题目 700. 二叉搜索树中的搜索题解递归实现 题目 98. 验证二叉搜索树题解中序遍历非递归实现中序遍历递归实现上下限递归 题目 938. 二叉搜索树的范围和题解中序遍历…