Linux内存模型

news2024/11/19 5:25:58

sparse内存模型

  • 前言
  • 1.SPARSEMEM原理:
  • 2.vmemmap在虚拟地址空间位置
  • 3.virt,phys,page,pfn之间的转换关系
    • 3.1内核态虚拟地址和物理内存地址转换关系
    • 3.2页帧pfn、物理内存的page指针的关系
    • 3.3其他快捷的转换
  • 总结

前言

Linux中的物理内存被按页框划分,每个页框都会对应一个struct page结构体存放元数据,也就是说每块页框大小的内存都要花费sizeof(struct page)个字节进行管理
内存模型的设计则主要是权衡以下两点(空间与时间):

  1. 尽量少的消耗内存去管理众多的struct page
  2. pfn_to_page和page_to_pfn的转换效率。

稀疏内存模型是当前内核默认的选择,从2005年被提出后沿用至今,但中间经过几次优化,包括:CONFIG_SPARSEMEM_VMEMMAP和CONFIG_SPARSEMEM_EXTREME的引入,这两个配置通常是被打开的,下面的原理介绍也会基于它们开启的情况。

1.SPARSEMEM原理:

  • section的概念:
    SPARSEMEM内存模型引入了section的概念,可以简单将它理解为struct page的集合(数组)。内核使用struct mem_section去描述section,定义如下:
struct mem_section {
        unsigned long section_mem_map;
        /* See declaration of similar field in struct zone */
        unsigned long *pageblock_flags;
};

其中的section_mem_map成员存放的是struct page数组的地址,每个section可容纳PFN_SECTION_SHIFT个struct page,arm64地址位宽为48bit时定义了每个section可囊括的地址范围是1GB。

  • 全局变量**mem_section
    内核中用了一个二级指针struct mem_section **mem_section去管理section,我们可以简单理解为一个动态的二维数组。所谓二维即内核又将SECTIONS_PER_ROOT个section划分为一个ROOT,ROOT的个数不是固定的,根据系统实际的物理地址大小来分配。
  • 物理页帧号PFN
    SPARSEMEM将PFN差分成了三个level,每个level分别对应:ROOT编号、ROOT内的section偏移、section内的page偏移。(可以类比多级页表来理解)
  • vmemmap区域
    vmemmap区域是一块起始地址是VMEMMAP_START,范围是2TB的虚拟地址区域,位于kernel space。以section为单位来存放strcut page结构的虚拟地址空间,然后线性映射到物理内存。
  • 内存热插拔
    SPARSEMEM中section是最小管理单元。内存热插拔也是以section为单位,下图中画的热插拔单位是一个section(ARM64是1GB),通常会大于等于一个section。
    通过下图来可以很好的串联上面几个概念:
    在这里插入图片描述
  • PFN和struct page的转换:
    SPARSEMEM中__pfn_to_page和__page_to_pfn的实现如下:
#define __pfn_to_page(pfn)      (vmemmap + (pfn))
#define __page_to_pfn(page)     (unsigned long)((page) - vmemmap)      
#define vmemmap        ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))

其中vmemmap指针指向VMEMMAP_START偏移memstart_addr的地址处,memstart_addr则是根据物理起始地址PHYS_OFFSET算出来的偏移,上图画出了三者之间的关系。

2.vmemmap在虚拟地址空间位置

内核虚拟地址空间布局随着内核的迭代不断变化,具体细节可以查看vmlinux.lds和arch/arm64/include/asm/memory.h等文件。举例如下:
linux4.9的内核地址空间布局:
在这里插入图片描述
linux5.4的内核地址空间布局:
在这里插入图片描述

3.virt,phys,page,pfn之间的转换关系

3.1内核态虚拟地址和物理内存地址转换关系

#define PAGE_OFFSET     UL(0xffffffc000000000)
/* PHYS_OFFSET - the physical address of the start of memory. */
#define PHYS_OFFSET     ({ memstart_addr; })
//把内核态虚拟地址转成物理地址
#define __virt_to_phys(x)   (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET))
//把物理内存地址转成内核态虚拟地址
#define __phys_to_virt(x)   ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))

3.2页帧pfn、物理内存的page指针的关系

#define ARCH_PFN_OFFSET     (PAGE_OFFSET >> PAGE_SHIFT)
//内存单元page指针数组,mem_map+0代表第1个内存单元page,mem_map+1代表第2个内存单元page...
struct page *mem_map;
//把页帧转成内存单元对应的page
#define __pfn_to_page(pfn)  (mem_map + ((pfn) - ARCH_PFN_OFFSET))
//把内存单元对应的page转成页帧
#define __page_to_pfn(page) ((unsigned long)((page) - mem_map) + ARCH_PFN_OFFSET)
//把内存单元对应page转成页帧
#define page_to_pfn __page_to_pfn
//把页帧转成其内存单元对应page
#define pfn_to_page __pfn_to_page

3.3其他快捷的转换

//把内核虚拟地址转成页帧
#define virt_to_pfn(kaddr)  (__pa(kaddr) >> PAGE_SHIFT)
//把页帧转成内核虚拟地址
#define pfn_to_virt(pfn)    __va((pfn) << PAGE_SHIFT)
//把内核虚拟地址转成其内存单元对应page
#define virt_to_page(addr)  pfn_to_page(virt_to_pfn(addr))
//把内存单元对应page转成内核虚拟地址
#define page_to_virt(page)  pfn_to_virt(page_to_pfn(page))
//把内核态虚拟地址转成物理地址
#define __pa(x)         __virt_to_phys((unsigned long)(x))
//把物理地址转成内核态虚拟地址
#define __va(x)         ((void *)__phys_to_virt((phys_addr_t)(x)))

总结

  • 高效
    通过上面__pfn_to_page的实现可以看出其仅用一步计算即可找到对应的struct page。

  • 省内存
    那另一个目标节省内存是如何做到的呢?答案就是按需分配,内存空洞或者被拔掉的内存条,我们不给它分配存放struct page的物理内存(只有虚拟内存)。

  • 物理内存page、页帧pfn、内核虚拟地址virt、物理内存地址phys的转换关系

virt=phys-PHYS_OFFSET + PAGE_OFFSET
pfn=phys/4K
page=mem_map + (pfn - ARCH_PFN_OFFSET)

连续两个内存单元,内核虚拟地址virt差0x1000,即4K;phys物理地址相差0x1000;page指针相差0x40,struct page 大小sizeof(struct page)正是0x40;页帧pfn相差1。

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

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

相关文章

408 考研《操作系统》第二章第五节:信号量机制和用信号量机制实现进程互斥、同步、前驱关系

文章目录教程1. 信号量机制1.1 概念1.2 信号量机制——整型信号量1.3 信号量机制——记录型信号量&#xff08;important&#xff09;1.4 总结2. 用信号量机制实现进程互斥、同步、前驱关系2.1 信号量机制实现进程互斥&#xff08;important&#xff09;2.2 信号量机制实现进程…

java基于SpringBoot的在线答疑系统的研究与实现-计算机毕业设计

项目介绍 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大师生的喜爱&#xff0c;也逐渐进入了每个学生的使用。互联网具有便利性&#xff0c;速度快&#xff0c;效率高&#xff0c;成本低等优点。 因此&#xff0c;构建符合…

【matplotlib】2-使用统计函数绘制简单图形

文章目录使用统计函数绘制简单图形1.函数bar()--用于绘制柱状图2.函数barh()--用于绘制条形图3.函数hist()--用于绘制条形图4.函数pie()--用于绘制饼图5.函数polar()--用于绘制极线图6.函数scatter()--用于绘制气泡图7.函数stem()--用于绘制棉棒图8.函数boxplot()--用于绘制箱线…

openGauss洗冤录 之 copy from

openGauss洗冤录 之 copy from 引子 之前一篇《测评报告&#xff1a;文件导入哪家强&#xff1f;》关于openGauss性能与预期不符的问题留下了个坑&#xff0c;今天回来填坑。 前文提到使用openGauss的copy from导入csv文件耗时是mysql的2倍&#xff0c;是PostgreSQL的6倍&#…

下载nacos-server-1.1.4安装包,使用mvn打包

git官方地址下载nacos-server-1.1.4.zip速度太慢&#xff0c;码云上下载地址没有安装包。采用从码云上下载源码&#xff0c;自行打包。(https://gitee.com/mirrors/Nacos/tree/1.1.4)下载完成之后&#xff0c;进入项目目录如图 下载源码后 &#xff0c;解压 本地在本文件夹 在d…

这十套练习,教你如何用Pandas做数据分析(03)

练习3-数据分组 探索酒类消费数据 步骤1 导入必要的库 运行以下代码 import pandas as pd 步骤2 从以下地址导入数据 运行以下代码 path3 ‘…/input/pandas_exercise/pandas_exercise/exercise_data/drinks.csv’ #‘drinks.csv’ 步骤3 将数据框命名为drinks 运行以下代…

SpringBoot+Vue实现前后端分离的航空售票管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

JavaScript(一):编写位置、输入输出语句

JavaScript入门一、 JavaScript编写位置二、输入输出语句一、 JavaScript编写位置 &#xff08;1&#xff09;编写到script标签中 控制浏览器弹出一个警告框 alert("警告内容")让计算机在页面中输出一个内容 document.write() /*可以向body中输出一个内容*/向控制…

基于java+springboot+mybatis+vue+mysql的自媒体社区平台

项目介绍 近几年来自媒体平台的发展越来越迅猛&#xff0c;并逐渐成为新闻信息传播的主流模式&#xff0c;自媒体平台的内容构成没有主要的核心&#xff0c;新闻信息的探讨和传播环境比较自由&#xff0c;与此同时自媒体平台概念的应用与发展,赋予了普通民众发表自己感想的权利…

OneUI 5.5.0 for HTML/PHP/VueJS

OneUI 是一个高度通用的 Bootstrap 管理仪表板模板和 UI 框架&#xff0c;支持 Laravel&#xff0c;可让您以相同的速度和稳健的布局创建各种网站。它是使用 Sass 和 ECMAScript 6 (ES6) 开发的&#xff0c;并为开发人员提供了各种智能工具&#xff0c;如 webpack5、Babel 7、G…

如何避免SCI写作中的中式思维以及无处不在的Chinglish

现在随着全球经济的下行&#xff0c;很多小伙伴都选择了延时就业&#xff0c;因此更多的人开始考研和考博。新东方大学生学习与发展中心发布的《新东方2023考研报告》预测&#xff1a;2023考研报名将超过520万人。俗话说&#xff08;我道听途说的&#xff09;&#xff1a;一入科…

一文教你数据结构体栈和队列的实现

前言&#xff1a; 关于c语言的学习已经差不多更新完毕&#xff0c;如果发现个别知识点&#xff0c;我还会继续更新&#xff0c;但目前已经准备往c和数据结构的重心挪动&#xff0c;这篇文章就是向大家讲述数据结构中栈和队列的实现。 &#x1f49e; &#x1f49e; 欢迎来到小…

VoIP通话-基于SIP协议的Asterisk(一)-实现流程

文章首发及后续更新&#xff1a;https://mwhls.top/4122.html&#xff0c;无图/无目录/格式错误/更多相关请至首发页查看。 新的更新内容请到mwhls.top查看。 欢迎提出任何疑问及批评&#xff0c;非常感谢&#xff01; VoIP通话-基于SIP协议的Asterisk该篇仅包含实现流程&#…

实验12 动态查找2022

A. DS二叉排序树之创建和插入 给出一个数据序列&#xff0c;建立二叉排序树&#xff0c;并实现插入功能 对二叉排序树进行中序遍历&#xff0c;可以得到有序的数据序列 输入 第一行输入t&#xff0c;表示有t个数据序列 第二行输入n&#xff0c;表示首个序列包含n个数据 第…

Vue 基础详解 | 系统性学习 | 无知的我费曼笔记

无知的我正在复盘Vue 该笔记特点是 重新整理了涉及资料的一些语言描述、排版而使用了自己的描述对一些地方做了补充说明。比如解释专有名词、类比说明、对比说明、注意事项提升了总结归纳性。尽可能在每个知识点上都使用一句话 || 关键词概括更注重在实际上怎么应用提出并回答…

spring——AOP面向切面编程—— 自动代理——根据 Bean 名称创建代理对象根据切面中信息创建代理对象...

自动代理 在前面的案例中&#xff0c;所有目标对象(Target Bean)的代理对象(Proxy Bean)都是在 XML 配置中通过 ProxyFactoryBean 创建的。 但在实际开发中&#xff0c;一个项目中往往包含非常多的 Bean&#xff0c; 如果每个 Bean 都通过 ProxyFactoryBean 创建&#xff0c;那…

MySQL~InnoDB关键特性(插入缓存、俩次写、自适应哈希索引、异步IO

一般情况下&#xff0c;主键是行唯一的标识符。通常应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此&#xff0c;插入聚集索引一般是顺序的&#xff0c;不需要磁盘的随机读取。因为&#xff0c;对于此类情况下的插入&#xff0c;速度还是非常快的。 如果索引…

Selenium4+Python3系列 - 测试框架的设计与开发

框架搭建 整个框架的实现&#xff0c;大约也就1.5天&#xff0c;关于框架的开发并不是很难&#xff0c;主要难在测试报告增加失败自动截图功能和echart的饼子图统计功能&#xff0c;两者的整合花了近半天的时间吧。 效果&#xff1a; 1、核心思想 延续使用Page Object和Page …

RabbitMQ入门(三)消息应答与发布确认

前言&#xff1a; 消息应答与发布确认都是保证消息不丢失。而重复消费问题则是消息幂等性。&#xff08;之后会说幂等性&#xff09; 消息应答&#xff1a; 应答功能属于消费者&#xff0c;消费者在接收到消息并且处理该消息之后&#xff0c;告诉 rabbitmq 它已经处理了&…

深度学习——残差网络(ResNet)笔记

残差网络&#xff1a;经常使用的网络之一 1.随着神经网络的不断加深能改进精度吗&#xff1f; 不一定 ①蓝色五角星表示最优值&#xff0c;Fi闭合区域表示函数&#xff0c;闭合区域的面积代表函数的复杂程度。在这个区域能够找到一个最优的模型&#xff08;区域中的一个点表…