当前位置: 首页 > news >正文

Linux系统编程——详解页表

目录

一、前言

二、深入理解页表

三、页表的实际组成

四、总结:


一、前言

       页表是我们之前在讲到程序地址空间的时候说到的,它是物理内存到进程程序地址空间的一个桥梁,通过它物理内存的数据和代码才能映射到进程的程序地址空间中,在信号这一节我们又提到了内核空间的页表,讲到了该内核级页表不同于前面说的用户级页表是每个进程都有的,内核级页表整个系统只有一份。

      但是之前我们对页表的理解还都处于一个比较简单的层面,事实上页表的实现还是比较复杂的,这次我们深入理解一下页表的构成及其功能。

二、深入理解页表

这是我们之前所理解的简化版的页表, 我们将页表的映射功能抽象成了两栏 ,实际上页表并不只有简单的两栏,其比较复杂,且不是用一张表就可以表述出来的

为了方便理解,我们暂且对复杂的页表结构做简单抽象,以一级页表来表示

物理地址和虚拟地址我们都已经知道了是什么了,剩下三栏中都分别代表什么呢?

1、RWX权限:我们知道Linux中一切皆文件,这里即我们所熟知的读、写、执行权限,表示的是进程对物理内存的访问权限 。我们直到硬件是不具备有访问控制能力的,也就是谁都可以对硬件进行读写,但是得益于操作系统,为了安全性,软件限制了我们的访问。

2、U/K权限:U表示User,K表示Kernel,即表示的用户和内核,就是在内核中的信号一篇中提到的用户态和内核态,用以区分访问内存的用户权限和内核权限。

3、是否命中:当CPU需要访问指定内存的数据的时候,会用虚拟地址通过页表向物理内存中查询数据。但是程序中的数据不是一下子全部加载到物理内存的,即页表中可能不存在指定的物理内存,所以CPU需要访问数据的时候,可能会存在一次找不到的情况,称为 未命中。

当CPU访问数据没有命中时,整个进程会从CPU上拉下来 先不运行,接着操作系统会将未命中的数据从磁盘程序中加载到指定的物理内存中,然后CPU才会再次运行此进程。

  所以是否命中这一栏其实是 表示的是此次CPU访问数据是否在物理内存中找到了。

这种进程数据不一次性加载到物理内存的机制, 是因为进程地址空间的存在才存在的.

可以允许进程在使用指定数据或代码的时候才将代码和数据真正加载到物理内存中. 这样可以更有效地利用内存资源

我们知道了CPU从虚拟地址到物理内存的数据查询机制,下面看一下页表是以什么形式存在的。

三、页表的实际组成

我们以32位环境为例,即进程地址空间和物理内存最大都为4GB,如果使用一级页表(即只使用一张页表),想要将虚拟地址空间和物理地址一一对应下来,这个页表需要储存多少行条目?

如果页表的一行只表示一个地址,那么32位的计算机就有着2的32次方个地址,然而页表中的一行不止存储一个地址,至少有两个,且在32位环境下地址的大小为4字节,所以页表中一行条目的大小是8个字节,要存储所有的地址的话这个页表得有多大呢?2^32 * 8 = 34,359,738,368,单位是字节,一共是32GB,而我们的物理内存最大才是4GB.很明显,以一级页表来将虚拟内存对应的物理内存全部映射到是不可能的。

所以事实上,在操作系统中的页表是多级页表,在32位系统中,采用的是两级页表的形式。


在对二级页表做介绍之前我们先来补充一些概念:

在32位环境下,物理内存和虚拟地址空间大小都是4GB,同时在CPU访问数据时,提供的虚拟地址也就是32位的。虚拟地址和物理地址的映射需要通过页表来完成,CPU需要有能力提供覆盖 所有物理地址内存的地址,32位环境下,就是32位进制,虽然CPU给页表提供的虚拟地址是32位的,但是却不是直接将32位作为一个整体在页表中查找物理地址的。而是将32位二进制分为了 10+10+12的形式。即:

  1. 虚拟地址和物理地址:在32位系统中,虚拟地址和物理地址的空间都是4GB。
  2. 虚拟地址的处理:虽然虚拟地址是32位的,CPU在查找物理地址时并不会直接使用整个32位地址,而是将其拆分成三段。
  3. 地址拆分的方式:虚拟地址被分为三部分:前两部分各有10位,最后一部分有12位。这样做是为了有效地在内存中查找和映射物理地址。
// CPU提供的32位二进制地址
// 会分为10、10、12位的三部分来进行查找
0000 0000 00  0000 0000 00  0000 0000 0000
xxxx xxxx xx  yyyy yyyy yy  zzzz zzzz zzzz

事实上CPU以这样的形式查找物理内存是因为页表设计形式是下面这样的:

32位环境下,也表映射的实现使用的是二级页表,情况如下:

可以看到在二级页表中出现了page这一框,这个page又是什么呢?

在之前我们介绍Linux的文件系统的时候,讲到 操作系统的I/O操作的基本单位通常都是4KB,为了方便操作操作系统也会以4KB为单位的大小来管理内存,即操作系统会将物理内存以4KB位基本单位,并将其称为页或者页框,也就是这里的 page 。除了物理内存之外,磁盘中的程序在进行编译的时候也是按照4KB为单位划分好的,程序中的4KB单位被称为 页帧

 

那么操作系统对于程序地址空间也是按照4KB为基本单位进行管理的。 

 Linux内核中的page是一个结构体如下:

所以4GB的内存是 4*1024*1024*1024 字节,4KB大小是 4*1024 字节,所以说操作系用中会存在着 1024*1024个page ,所以为了方便管理,操作系统会将这些page统一以一个数据结构维护起来,最终对于内存的管理其实就是对于此数据结构的管理。

所以CPU对于物理内存的查找实际上是这样的:

  1. 首先使用的是虚拟地址的最高的10位,在页目录中查找到对应的页表的地址,再通过该地址查找到对应的页表。
  2. 接着通过虚拟地址的中间的10位查找对应的page的起始地址,这个page的起始地址其实就是个真实的物理地址,找到的就是物理内存中的一页page
  3. 最后虚拟地址的最后12位起到的是一个偏移量的作用,我们称虚拟地址的最后12位为 页内偏移量
  4. 所以我们找到page的起始地址,将虚拟地址的最低12位作为偏移量,就能够找到一个准确的物理地址。

但是这个虚拟地址的最后12位可以刚好覆盖完一个page的全部地址吗?我们可以计算一下:page的大小是4KB,即4*1024=4*2^10=2^12,而虚拟地址的最低12位刚好可以覆盖到page的全部地址。

 

四、总结

1、进程虚拟地址和物理内存的解耦

  1. 在二级页表中,每个页表条目记录的是页面(page)的位置,未加载的页面会存储为null。当程序的数据没有加载到某个页面时,CPU查找时就会发生“未命中”情况。
  2. 这意味着,CPU在查找物理内存时,不关心页面的内容,只关心该页面是否存在。程序的数据是以页面为单位加载到内存中的。
  3. 通过页表,虚拟地址和物理内存之间实现了解耦。虚拟地址到物理地址的转换过程中,只能判断物理地址是否存在,而不会涉及具体的数据内容。

2、页表设计的优点

  • 节省内存

    • 如果使用一级页表,整个4GB的内存地址空间都需要为每个页面创建一个对应的页表项,这会占用大量内存。
    • 而使用多级页表,页目录的大小一般为KB级别,且由于第二级页表是按需创建的,因此只在需要时才分配内存。这样可以显著节省内存。最坏情况下,内存占用也只是MB级别。
  • 方便管理

    • 多级页表的结构类似于一颗多叉树。第一层页表(页目录)指向第二层页表,第二级页表就像树的节点一样,可以按需创建、删除和管理。
    • 这种结构使得管理更加灵活和高效,尤其是当内存需求不均匀时,可以动态分配和释放内存。

相关文章:

Linux系统编程——详解页表

目录 一、前言 二、深入理解页表 三、页表的实际组成 四、总结: 一、前言 页表是我们之前在讲到程序地址空间的时候说到的,它是物理内存到进程程序地址空间的一个桥梁,通过它物理内存的数据和代码才能映射到进程的程序地址空间中&#xff…...

SpringBoot + HttpSession 自定义生成sessionId

SpringBoot HttpSession 自定义生成sessionId 业务场景实现方案 业务场景 最近在做用户登录过程中,由于默认ID是通过UUID创建的,缺乏足够的安全性,决定要自定义生成 sessionId。 实现方案 正常的获取session方法如下: HttpSe…...

循环对称复高斯分布(Circularly Symmetric Complex Gaussian Distribution)

一、引言 循环对称复高斯分布(Circularly Symmetric Complex Gaussian Distribution,简称CSCG)在无线通信、信号处理等领域具有广泛的应用。作为一种特殊的复高斯分布,CSCG具有独特的性质,如循环对称性、高斯性等&…...

xinput1_3.dll放在哪里?当xinput1_3.dll丢失时的应对策略:详细解决方法汇总

在计算机系统的运行过程中,我们偶尔会遇到一些令人困扰的问题,其中xinput1_3.dll文件丢失就是较为常见的一种情况。这个看似不起眼的动态链接库文件,实则在许多软件和游戏的正常运行中发挥着至关重要的作用。一旦它丢失,可能会导致…...

基于STM32的智能家居环境监控系统设计

目录 引言系统设计 硬件设计软件设计系统功能模块 环境监控模块控制模块显示模块系统实现 硬件实现软件实现系统调试与优化结论与展望 1. 引言 随着智能家居技术的发展,环境监控系统已经成为家居管理的重要组成部分。智能家居环境监控系统通过实时监测室内温度、湿…...

Vscode + gdbserver远程调试开发板指南:

本章目录 步骤环境准备网络配置vscode配置步骤 (全图示例)开发板配置开始调试注意: 每次断开之后,开发板都需要重新启动gdbserver才可调试。 参考链接: 步骤 环境准备 将交叉编译链路径加入$PATH变量:确保系统能够找到所需的工具。 export PATH$PATH:/p…...

大表:适用于结构化数据的分布式存储系统

大家觉得有意义和帮助记得及时关注和点赞!!! 译者序摘要1 引言2 数据模型 2.1 行(Row)2.2 Column Families(列族) 2.2.1 设计2.2.2 column key 的格式:family:qualifier2.2.3 访问控制和磁盘/内存记账(acco…...

深入解析MVCC中Undo Log版本底层存储读取逻辑

一、引言 多版本并发控制(MVCC,Multi-Version Concurrency Control)是一种广泛应用于关系数据库管理系统中的并发控制技术。它通过保存数据的历史版本,使得在事务并发执行时,每个事务都能看到数据的一致性视图。在MVC…...

游戏引擎学习第64天

代码改的我看的比较懵 原视频可以去这个网站去看 https://guide.handmadehero.org/ 回顾我们在模拟区域方面的进展 在目前的情况下,如果有很多任务需要完成,可以进行分解。在昨天收到的改变中,决定将任务分解成模拟区域。模拟区域是可以随时…...

Effective C++ 条款33:避免遮掩继承而来的名称

文章目录 条款33:避免遮掩继承而来的名称为什么避免遮掩?如何避免遮掩?1. 使用 using 声明式2. 使用转交函数 (Forwarding Functions) 总结 条款33:避免遮掩继承而来的名称 在 C 中,派生类(derived class&…...

UEFI Spec 学习笔记---4 - EFI System Table(1)

4 - EFI System Table 本章节主要介绍的是 UEFI Image 的 Entry point(在 UEFI 固件执行的时候,都是直接调用入口函数并且执行从而调用其他的 driver)。 UEFI Image 主要是有三类:UEFI boot service driver、UEFI runtime drive…...

【微信小程序】3|首页搜索框 | 我的咖啡店-综合实训

首页-搜索框-跳转 引言 在微信小程序中,首页的搜索框是用户交互的重要入口。本文将通过“我的咖啡店”小程序的首页搜索框实现,详细介绍如何在微信小程序中创建和处理搜索框的交互。 1. 搜索函数实现 onClickInput函数在用户点击搜索框时触发&#x…...

独一无二,万字详谈——Linux之文件管理

Linux文件部分的学习,有这一篇的博客足矣! 目录 一、文件的命名规则 1、可以使用哪些字符? 2、文件名的长度 3、Linux文件名的大小写 4、Linux文件扩展名 二、文件管理命令 1、目录的创建/删除 (1)、目录的创建 ① mkdir…...

React:前端开发领域的璀璨之星

亲爱的小伙伴们😘,在求知的漫漫旅途中,若你对深度学习的奥秘、Java 与 Python 的奇妙世界,亦或是读研论文的撰写攻略有所探寻🧐,那不妨给我一个小小的关注吧🥰。我会精心筹备,在未来…...

C/C++ 数据结构与算法【哈夫曼树】 哈夫曼树详细解析【日常学习,考研必备】带图+详细代码

哈夫曼树(最优二叉树) 1)基础概念 **路径:**从树中一个结点到另一个结点之间的分支构成这两个结点间的路径。 **结点的路径长度:**两结点间路径上的分支数。 **树的路径长度:**从树根到每一个结点的路径…...

基于NodeMCU的物联网窗帘控制系统设计

最终效果 基于NodeMCU的物联网窗帘控制系统设计 项目介绍 该项目是“物联网实验室监测控制系统设计(仿智能家居)”项目中的“家电控制设计”中的“窗帘控制”子项目,最前者还包括“物联网设计”、“环境监测设计”、“门禁系统设计计”和“小…...

喜报 | 擎创科技入围上海市优秀信创解决方案

近日,由上海市经信委组织的“2024年上海市优秀信创解决方案”征集遴选活动圆满落幕,擎创科技凭借实践经验优秀的《擎创夏洛克智能预警与应急处置解决方案》成功入选“2024年上海市优秀信创解决方案”名单。 为激发创新活力,发挥标杆作用&…...

windows10下使用沙盒多开uiautoanimation可行性验证

文章目录 ⭐前言⭐sandboxie下载使用⭐pyinstaller打包python的uiautoanimation成exe⭐结论⭐结束 ⭐前言 大家好,我是yma16,本文分享windows下使用沙盒多开uiautoanimation可行性验证。 背景 实现多开应用程序从而进行自动化控制,批量处理大…...

电脑报错wsdprintproxy.dll丢失?修复wsdprintproxy.dll文件缺失的实用方法

在使用电脑的过程中,我们可能会遇到各种各样的错误提示,其中之一就是系统提示wsdprintproxy.dll文件丢失。这个DLL文件是Windows操作系统中的一个重要组件,它通常与Windows的打印功能相关。当这个文件丢失或损坏时,可能会导致打印…...

Kubernetes 的资源管理方式

集群架构 Docker 是每一个节点(包括 Master 节点和 Node 节点)的运行时环境。 kubelet 负责控制所有容器的启动和停止等,保证每个节点(包括 Master 节点和 Node 节点)正常工作,并且帮助 Node 节点和 Maste…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求&#xff…...

2025季度云服务器排行榜

在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...