Linux:页表详解(虚拟地址到物理地址转换过程)
文章目录
- 前言
- 一、分页式存储管理
- 1.1 虚拟地址和页表的由来
- 1.2 物理内存管理与页表的数据结构
- 二、 多级页表
- 2.1 页表项
- 2.2 多级页表的组成
- 总结
前言
在我们之前的学习中,我们对于页表的认识仅限于虚拟地址到物理地址转换的桥梁,然而对于具体的转换实现以及更多页表实现的细节还是有认知模糊的,以下便详细解释页表的构成和功能

`
提示:以下是本篇文章正文内容,下面案例可供参考
一、分页式存储管理
1.1 虚拟地址和页表的由来
如果在没有虚拟内存和分⻚机制的情况下,每⼀个⽤⼾程序在物理内存上所对应的空间必须是连续的,如下图:
因为每⼀个程序的代码、数据⻓度都是不⼀样的,按照这样的映射⽅式,物理内存将会被分割成各种离散的、⼤⼩不同的块。经过⼀段运⾏时间之后,有些程序会退出,那么它们占据的物理内存空间可以被回收,导致这些物理内存都是以很多碎⽚的形式存在。如果再使用这段碎片空间只能是比这段空间小的程序来使用了
| 我们希望操作系统提供给⽤⼾的空间必须是连续的,但是物理内存最好不要连续。此时虚拟内存和分⻚便出现了,如下图所⽰: |

把物理内存按照⼀个固定的⻓度的⻚框进⾏分割,有时叫做物理⻚。每个⻚框包含⼀个物理⻚(page)。⼀个⻚的⼤⼩等于⻚框的⼤⼩。⼤多数 32位 体系结构⽀持 4KB 的⻚,⽽ 64位 体系结构⼀般会⽀持 8KB 的⻚。区分⼀⻚和⼀个⻚框是很重要的:
- ⻚框是⼀个存储区域;
- ⽽⻚是⼀个数据块,可以存放在任何⻚框或磁盘中。
有了这种机制,CPU 便并⾮是直接访问物理内存地址,⽽是通过虚拟地址空间来间接的访问物理内存地址。所谓的虚拟地址空间,是操作系统为每⼀个正在执⾏的进程分配的⼀个逻辑地址,在32位机上,其范围从0 ~ 4G-1。
操作系统通过将虚拟地址空间和物理内存地址之间建⽴映射关系,也就是⻚表,这张表上记录了每⼀对⻚和⻚框的映射关系,能让CPU间接的访问物理内存地址。
总结⼀下,其思想是将虚拟内存下的逻辑地址空间分为若⼲⻚,将物理内存空间分为若⼲⻚框,通过⻚表便能把连续的虚拟内存,映射到若⼲个不连续的物理内存⻚。这样就解决了使⽤连续的物理内存造成的碎⽚问题。
1.2 物理内存管理与页表的数据结构
假设⼀个可⽤的物理内存有 4GB 的空间。按照⼀个⻚框的⼤⼩ 4KB 进⾏划分, 4GB 的空间就是 4GB/4KB = 1048576 个⻚框。有这么多的物理⻚,操作系统肯定是要将其管理起来的,操作系统需要知道哪些⻚正在被使⽤,哪些⻚空闲等等。
内核⽤ struct page 结构表⽰系统中的每个物理⻚。通过struct page [ ] 数组的方式来对页表进行操作,因此每一个page都有下标,每一个物理内存的起始地址天然就知道了。申请物理内存就是查找page并作修改,并在内核上建立对应的数据结构关系
以上是省略图片,有没显示的参数,其中⽐较重要的⼏个参数:
- flags :⽤来存放⻚的状态。这些状态包括⻚是不是脏的,是不是被锁定在内存中等。flag的每⼀位单独表⽰⼀种状态,所以它⾄少可以同时表⽰出32种不同的状态。这些标志定义在<linux/page-flags.h>中。其中⼀些⽐特位⾮常重要,如PG_locked⽤于指定⻚是否锁定,PG_uptodate⽤于表⽰⻚的数据已经从块设备读取并且没有出现错误。
- _mapcount :表⽰在⻚表中有多少项指向该⻚,也就是这⼀⻚被引⽤了多少次。当计数值变为-1时,就说明当前内核并没有引⽤这⼀⻚,于是在新的分配中就可以使⽤它。
- virtual :是⻚的虚拟地址。通常情况下,它就是⻚在虚拟内存中的地址。有些内存(即所谓的⾼端内存)并不永久地映射到内核地址空间上。在这种情况下,这个域的值为NULL,需要的时候,必须动态地映射这些⻚。
4GB的内存是 4* 1024* 1024* 1024 字节,4KB大小是 4* 1024 字节,所以说操作系用中会存在着 1024*1024个page ,所以为了方便管理,操作系统会将这些page统一以一个数据结构维护起来,最终对于内存的管理其实就是对于此数据结构的管理。
二、 多级页表
2.1 页表项
页表项(Page Table Entry, PTE) 是页表中的基本单元,每个表项记录了一个虚拟页到物理页框的映射关系及其相关控制信息
物理地址和虚拟地址我们都已经知道了是什么了,剩下三栏中都分别代表什么呢?
1、RWX权限:我们知道Linux中一切皆文件,这里即我们所熟知的读、写、执行权限,表示的是进程对物理内存的访问权限 。我们直到硬件是不具备有访问控制能力的,也就是谁都可以对硬件进行读写,但是得益于操作系统,为了安全性,软件限制了我们的访问。
2、U/K权限:U表示User,K表示Kernel,即表示的用户和内核,就是在内核中的信号一篇中提到的用户态和内核态,用以区分访问内存的用户权限和内核权限。
3、是否命中:当CPU需要访问指定内存的数据的时候,会用虚拟地址通过页表向物理内存中查询数据。但是程序中的数据不是一下子全部加载到物理内存的,即页表中可能不存在指定的物理内存,所以CPU需要访问数据的时候,可能会存在一次找不到的情况,称为 未命中。
当CPU访问数据没有命中时,整个进程会从CPU上拉下来 先不运行,接着操作系统会将未命中的数据从磁盘程序中加载到指定的物理内存中,然后CPU才会再次运行此进程。
所以是否命中这一栏其实是 表示的是此次CPU访问数据是否在物理内存中找到了。
⻚表中的每⼀个表项,指向⼀个物理⻚的开始地址。在 32 位系统中,虚拟内存的最⼤空间是 4GB ,这是每⼀个⽤⼾程序都拥有的虚拟内存空间。既然需要让 4GB 的虚拟内存全部可⽤,那么⻚表中就需要能够表⽰这所有的 4GB 空间,那么就⼀共需要 4GB/4KB = 1048576 个表项。如下简略图所⽰:

⻚表中的物理地址,与物理内存之间,是随机的映射关系,哪⾥可⽤就指向哪⾥(物理⻚)。虽然最终使⽤的物理内存是离散的,但是与虚拟内存对应的线性地址是连续的。处理器在访问数据、获取指令时,使⽤的都是线性地址,只要它是连续的就可以了,最终都能够通过⻚表找到实际的物理地址。
2.2 多级页表的组成
| 由于页表自身含有的页表项也要占据内存空间,对于单级页表来说它本身需要2^20个页表项,如果让每个进程都用单级页表进行操作,那么会极大浪费空间。多级页表通过分层索引和按需分配解决单级页表过大的问题 |
我们以32位环境为例,即进程地址空间和物理内存最大都为4GB,如果使用一级页表(即只使用一张页表),想要将虚拟地址空间和物理地址一一对应下来,这个页表需要储存多少行条目?
- 单级页表的问题
单级页表设计:
页表需要为所有可能的虚拟页预留条目,无论是否被使用。
总条目数 = 4GB / 4KB = 1,048,576条(即100万个条目)。
每个条目大小:4字节(存储物理页框号和控制位)。
总内存占用 = 1M条 × 4B = 4MB。
关键问题:
即使进程仅使用100个页(400KB数据),单级页表也必须占用4MB内存,99.99%的条目是浪费的!
所以事实上,在操作系统中的页表是多级页表,在32位系统中,采用的是两级页表的形式。
在32位环境下,物理内存和虚拟地址空间大小都是4GB,同时在CPU访问数据时,提供的虚拟地址也就是32位的。虚拟地址和物理地址的映射需要通过页表来完成,CPU需要有能力提供覆盖 所有物理地址内存的地址,32位环境下,就是32位进制,虽然CPU给页表提供的虚拟地址是32位的,但是却不是直接将32位作为一个整体在页表中查找物理地址的。而是将32位二进制分为了 10+10+12的形式。即:
- 虚拟地址和物理地址:在32位系统中,虚拟地址和物理地址的空间都是4GB。
- 虚拟地址的处理:虽然虚拟地址是32位的,CPU在查找物理地址时并不会直接使用整个32位地址,而是将其拆分成三段。
- 地址拆分的方式:虚拟地址被分为三部分:前两部分各有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


总结
- 进程虚拟地址和物理内存的解耦
- 在二级页表中,每个页表条目记录的是页面(page)的位置,未加载的页面会存储为null。当程序的数据没有加载到某个页面时,CPU查找时就会发生“未命中”情况。
- 这意味着,CPU在查找物理内存时,不关心页面的内容,只关心该页面是否存在。程序的数据是以页面为单位加载到内存中的。
- 通过页表,虚拟地址和物理内存之间实现了解耦。虚拟地址到物理地址的转换过程中,只能通过对页表项的特定数据来判断物理地址是否存在,而不会涉及具体的数据内容。
- 页表设计的优点
-
节省内存:
-
如果使用一级页表,整个4GB的内存地址空间都需要为每个页面创建一个对应的页表项,这会占用大量内存。
而使用多级页表,页目录的大小一般为KB级别,且由于第二级页表是按需创建的,因此只在需要时才分配内存。这样可以显著节省内存。最坏情况下,内存占用也只是MB级别。
方便管理: -
多级页表的结构类似于一颗多叉树。第一层页表(页目录)指向第二层页表,第二级页表就像树的节点一样,可以按需创建、删除和管理。
这种结构使得管理更加灵活和高效,尤其是当内存需求不均匀时,可以动态分配和释放内存。
相关文章:
Linux:页表详解(虚拟地址到物理地址转换过程)
文章目录 前言一、分页式存储管理1.1 虚拟地址和页表的由来1.2 物理内存管理与页表的数据结构 二、 多级页表2.1 页表项2.2 多级页表的组成 总结 前言 在我们之前的学习中,我们对于页表的认识仅限于虚拟地址到物理地址转换的桥梁,然而对于具体的转换实现…...
AF3 OpenFoldDataLoader类解读
AlphaFold3 data_modules 模块的 OpenFoldDataLoader 类继承自 PyTorch 的 torch.utils.data.DataLoader。该类主要对原始 DataLoader 做了批数据增强与控制循环迭代次数(recycling)相关的处理。 源代码: class OpenFoldDataLoader(torch.utils.data.DataLoader):def __in…...
初见TypeScript
类型语言,在代码规模逐渐增大时,类型相关的错误难以排查。TypeScript 由微软开发,它本质上是 JavaScript 的超集,为 JavaScript 添加了静态类型系统,让开发者在编码阶段就能发现潜在类型错误,提升代码质量&…...
常见的 JavaScript 框架和库
在现代前端开发中,JavaScript框架和库成为了构建高效、可维护应用程序的关键工具。本文将介绍四个常见的JavaScript框架和库:React、Vue.js、Angular 和 Node.js,并探讨它们的特点、使用场景及适用场合。 1. React — 构建用户界面的JavaScri…...
机器学习代码基础——ML2 使用梯度下降的线性回归
ML2 使用梯度下降的线性回归 牛客网 描述 编写一个使用梯度下降执行线性回归的 Python 函数。该函数应将 NumPy 数组 X(具有一列截距的特征)和 y(目标)作为输入,以及学习率 alpha 和迭代次数,并返回一个…...
PostgreSQL 一文从安装到入门掌握基本应用开发能力!
本篇文章主要讲解 PostgreSQL 的安装及入门的基础开发能力,包括增删改查,建库建表等操作的说明。navcat 的日常管理方法等相关知识。 日期:2025年4月6日 作者:任聪聪 一、 PostgreSQL的介绍 特点:开源、免费、高性能、关系数据库、可靠性、稳定性。 官网地址:https://w…...
WEB安全--内网渗透--LMNTLM基础
一、前言 LM Hash和NTLM Hash是Windows系统中的两种加密算法,不过LM Hash加密算法存在缺陷,在Windows Vista 和 Windows Server 2008开始,默认情况下只存储NTLM Hash,LM Hash将不再存在。所以我们会着重分析NTLM Hash。 在我们内…...
查询条件与查询数据的ajax拼装
下面我将介绍如何使用 AJAX 动态拼装查询条件和获取查询数据,包括前端和后端的完整实现方案。 一、前端实现方案 1. 基础 HTML 结构 html 复制 <div class"query-container"><!-- 查询条件表单 --><form id"queryForm">…...
8.用户管理专栏主页面开发
用户管理专栏主页面开发 写在前面用户权限控制用户列表接口设计主页面开发前端account/Index.vuelangs/zh.jsstore.js 后端Paginator概述基本用法代码示例属性与方法 urls.pyviews.py 运行效果 总结 欢迎加入Gerapy二次开发教程专栏! 本专栏专为新手开发者精心策划了…...
室内指路机器人是否支持与第三方软件对接?
嘿,你知道吗?叁仟室内指路机器人可有个超厉害的技能,那就是能和第三方软件 “手牵手” 哦,接下来就带你一探究竟! 从技术魔法角度看哈:好多室内指路机器人都像拥有超能力的小魔法师,采用开放式…...
Apache BookKeeper Ledger 的底层存储机制解析
Apache BookKeeper 的 ledger(账本)是其核心数据存储单元,底层存储机制结合了日志追加(append-only)、分布式存储和容错设计。Ledger 的数据存储在 Bookie 节点的磁盘上,具体实现涉及 Journal(日…...
从代码上深入学习GraphRag
网上关于该算法的解析都停留在大概流程上,但是具体解析细节未知,由于代码是PipeLine形式因此阅读起来比较麻烦,本文希望通过阅读项目代码来解析其算法的具体实现细节,特别是如何利用大模型来完成图谱生成和检索增强的实现细节。 …...
通俗地讲述DDD的设计
通俗地讲述DDD的设计 前言为什么要使用DDDDDD架构分层重构实践关键问题解决方案通过领域事件机制解耦服务依赖:防止逻辑下沉 领域划分电商场景下的领域划分 结语完结撒花,如有需要收藏的看官,顺便也用发财的小手点点赞哈,…...
【Redis】通用命令
使用者通过redis-cli客户端和redis服务器交互,涉及到很多的redis命令,redis的命令非常多,我们需要多练习常用的命令,以及学会使用redis的文档。 一、get和set命令(最核心的命令) Redis中最核心的两个命令&…...
网络安全技术文档
网络安全技术文档 1. 概述 网络安全是指通过技术手段和管理措施,保护网络系统的硬件、软件及其数据不受偶然或恶意破坏、更改、泄露,确保系统连续可靠运行,网络服务不中断。 2. 常见网络威胁 2.1 攻击类型 DDoS攻击:分布式拒…...
微前端随笔
✨ single-spa: js-entry 通过es-module 或 umd 动态插入 js 脚本 ,在主应用中发送请求,来获取子应用的包, 该子应用的包 singleSpa.registerApplication({name: app1,app: () > import(http://localhost:8080/app1.js),active…...
【36期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深A股当天逐笔大单交易数据及接口API说明文档
在量化分析领域,实时且准确的数据接口是成功的基石。经过多次实际测试,我将已确认可用的数据接口分享给正在从事量化分析的朋友们,希望能够对你们的研究和工作有所帮助,接下来我会用Python、JavaScript(Node.js&…...
C++中的浅拷贝和深拷贝
浅拷贝只是将变量的值赋予给另外一个变量,在遇到指针类型时,浅拷贝只会把当前指针的值,也就是该指针指向的地址赋予给另外一个指针,二者指向相同的地址; 深拷贝在遇到指针类型时,会先将当前指针指向地址包…...
二叉树与红黑树核心知识点及面试重点
二叉树与红黑树核心知识点及面试重点 一、二叉树 (Binary Tree) 1. 基础概念 定义:每个节点最多有两个子节点(左子节点和右子节点) 术语: 根节点:最顶层的节点 叶子节点:没有子节点的节点 深度…...
GitHub 趋势日报 (2025年04月01日)
GitHub 趋势日报 (2025年04月01日) 本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星语言1punkpeye/awesome-mcp-serversA collection of MCP servers.⭐ 3280未指定2th-ch/youtube-musicYouTu…...
Java的SeleniumChromeDriver的常用方法
启动和关闭浏览器: driver.get(url):打开指定的URL。driver.quit():关闭浏览器并结束ChromeDriver会话。 元素定位: driver.findElement(By.id("elementId")):通过元素的ID定位。driver.findElement(By.cl…...
字符串、列表、元组、字典
字符串 双引号或者单引号中的数据,就是字符串 字符串输入 之前在学习input的时候,通过它能够完成从键盘获取数据,然后保存到指定的变量中; 注意:input获取的数据,都以字符串的方式进行保存,即…...
【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60‘ did not match any bands”
【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 【GEE学习笔记】报错解决:“Image.select: Band pattern ‘QA60’ did not match any bands” 文章目录 【GEE学习笔记】报错解决:“Image.selec…...
AI可以赋能的三农产品、机械与服务
三农赛道涵盖农业、农村和农民相关的产品与服务,涉及农资、农业机械、智能设备、农产品加工及数字化服务等多个领域。随着人工智能(AI)技术的飞速发展,AI正在通过赋能农业的生产、管理、销售等各个环节,推动传统农业向…...
ngx_timezone_update
定义在 src\os\unix\ngx_time.c void ngx_timezone_update(void) { #if (NGX_FREEBSD)if (getenv("TZ")) {return;}putenv("TZUTC");tzset();unsetenv("TZ");tzset();#elif (NGX_LINUX)time_t s;struct tm *t;char buf[4];s tim…...
车载诊断架构 --- 整车重启先后顺序带来的思考
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...
GESP C++三级 知识点讲解
C编程三级标准 (一)知识点详述 (1)了解二进制数据编码:原码、反码、补码。 (2)掌握数据的进制转换:二进制、八进制、十进制、十六进制。 (3)掌握位运算:与(&)、或(|)、非(~)、异或(^)、左移(<<)、右移(>>)的基本使用方法及原理。 (4)了解算法的概念与描述&…...
前端 vs 后端:技术分工详解——从用户界面到系统逻辑的全解析
前端(Frontend) 和 后端(Backend) 是软件开发中两个核心概念,分别对应用户直接交互的部分和系统背后的逻辑处理部分。它们共同构成完整的应用程序,但分工不同。 目录 一、前端(Frontend…...
Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结
以下是 Redis 除了数据类型外的核心功能 的详细说明,包含事务、流水线、发布/订阅、Lua 脚本的完整代码示例和表格总结: 1. Redis 事务(Transactions) 功能描述 事务通过 MULTI 和 EXEC 命令将一组命令打包执行,保证…...
JavaScript智能对话机器人——企业知识库自动化
引言 内部知识管理常面临信息分散、查找困难的问题。本文将使用Node.js和虎跃办公的智能对话API,构建企业级知识问答机器人,支持自然语言查询和自动学习。 核心技术 自然语言处理(NLP)意图识别机器学习模型微调REST API集成 代…...



