【进程空间】通过页表寻址的过程

news2024/11/18 10:35:53

文章目录

  • 前言
  • 介绍页表、页框、页目录的概念
    • 页框
    • 页表
    • 页目录
    • 页表和页目录的分配
  • 一级页表和二级页表
    • 一级页表
      • 寻址过程
    • 二级页表
      • 寻址过程
    • 一级页表和二级页表的对比

前言

我们知道每个进程都有属于自己的虚拟地址空间,且每个进程的虚拟地址都是统一的。要想通过虚拟地址访问物理地址,我们就需要借助页表来建立映射关系。下面对于如何借助页表来寻址展开详细解释(以32位操作系统为例)。

介绍页表、页框、页目录的概念

页框

页框(Page Frame)是物理内存中的固定大小的块,通常为4KB。在物理内存中,页框是用于存储实际数据的最小单元。假设内存大小为4GB,也就能划分出1024*1024个页框。当进程通过页表来访问物理地址时,其本质就是找到页框的地址。

在这里插入图片描述
于是,操作系统对内存的管理,就可以看成是对页框即块的管理。那内核中又是如何描述一个页框的呢?
在Linux内核中,使用struct page结构来描述内存中的每一页框。这个结构体定义在内核头文件include/linux/mm_types.h中。该结构体通常有以下字段:

  • flags:标志位,表示页面的各种状态
  • mapping:指向该页框所属的地址空间
  • index:该页框在地址空间中的偏移量
  • _maocount:记录该页框到页表条目数
  • _refcount:页面引用计数。表示有多少用户正在使用该页框

页表

页表是用于存储物理内存与虚拟内存地址之间的映射关系的结构。每个进程都有属于自己的页表。页表中的每一个表项,都对应着一个页框的物理地址。一个页表项(PTE)通常包括以下几个字段:

  • 页框基地址:页框的第一个字节的地址
  • 控制位:包括存在位(P)、读/写位(R/W)、超级用户位(U/S)等。

给出32位页表项的控制位示例:
在这里插入图片描述
(上图来自知乎)

再给出内核中描述页表项的结构体代码,该结构体其实是一个位段,所有变量加起来一共32个bite位,即4字节:

// 页表项(PTE)的定义
typedef struct {
    uint32_t present    : 1;  // 存在位
    uint32_t rw         : 1;  // 读/写位
    uint32_t us         : 1;  // 用户/超级用户位
    uint32_t pwt        : 1;  // 页级写穿透位
    uint32_t pcd        : 1;  // 页级缓存禁用位
    uint32_t accessed   : 1;  // 访问位
    uint32_t dirty      : 1;  // 脏位
    uint32_t pat        : 1;  // 页属性表位
    uint32_t global     : 1;  // 全局位
    uint32_t available  : 3;  // 可用位
    uint32_t page_frame_base : 20; // 页框基地址
} __attribute__((packed)) page_table_entry_t;

页表其本质就是这种结构体数组

页目录

页目录是用来管理页表的结构。页目录中每一表项都指着一张页表的物理地址。一个页目录项(PDE)通常包括以下几个字段:

  • 页表基地址:页表的首地址(物理)
  • 控制位:包括存在位(P)、读/写位(R/W)、超级用户位(U/S)等。

给出32位页目录项的控制位示例:
在这里插入图片描述
(上图来着知乎)
同样,给出内核中描述页目录项的代码:

// 页目录项(PDE)的定义
typedef struct {
    uint32_t present    : 1;  // 存在位
    uint32_t rw         : 1;  // 读/写位
    uint32_t us         : 1;  // 用户/超级用户位
    uint32_t pwt        : 1;  // 页级写穿透位
    uint32_t pcd        : 1;  // 页级缓存禁用位
    uint32_t accessed   : 1;  // 访问位
    uint32_t reserved   : 1;  // 保留位
    uint32_t ps         : 1;  // 页大小(通常为4KB页)
    uint32_t ignored    : 1;  // 忽略位
    uint32_t available  : 3;  // 可用位
    uint32_t page_table_base : 20; // 页表基地址
} __attribute__((packed)) page_directory_entry_t;

综上,我们知道了页框、页表、页目录的概念,以及彼此之间的联系。那么在一个进程建立的时候, 页表和页目录的内容是固定的吗? 答案是否定的。

页表和页目录的分配

在Linux内核中,新进程的页目录表的内容是动态增加的。这意味着页目录表和页表的分配更新会根据实际情况动态进行,而不是在创建进程时一次初始化所有的页表项。
大致步骤如下:

  1. 进程创建建立并初始化新页目录表。该表大部分内容为空,有部分指向共享内核。
  2. 访问虚拟地址,如果该地址对应的页表项不存在,触发页故障。内核捕捉这个故障,然后给进程分配对于的页表,并更新页目录表页页表

一级页表和二级页表

在操作系统中,分页机制可以采用单级页表和多级页表进行地址映射。linux采用的就是多级页表。不同的分页机制会导致寻址的空间成本不同(页表本身也占空间)。下面以一级页表和二级页表为例,分析各自的空间成本。
单级页表:只有一张大的页表来映射虚拟空间和物理空间。结构较为简单,直接映射。
多级页表:分层次的管理地址空间,且一般都有一张页目录表。结构较为复杂,需要多次转换地址。

一级页表

总共就一张表。

  • 页表项大小:通常每一个页表项都是4个字节,即32个比特位。
  • 页表项数目:因为4GB内存一共有1024*1024个页框,要想映射所有页框。也就需要1024*1024个页表项。

一级页表的总大小:4bite10241024=4MB

当我们采用一级页表。给出一个虚拟地址(32位),如何找到目标的物理地址(某一字节)呢?

寻址过程

将虚拟地址分解为两个部分:

  1. 页表索引:高20位。因为一张页表的总项数为1024*1024=2^20(页框数),虚拟地址的高20位用来表示页表项的位置。
  2. 页内偏移量:低12位。通过高20位能找到一个唯一的页表项,即页框的物理地址。一个页框占4096个字节,用12位比特位恰好能表示4096个不同的位置。于是通过低12位比特位的组合,我们就能找到页框内的唯一一个字节。

假设现在有一个虚拟地址为:0x0000 1005取出高20位的十进制值为1,低12位的十进制值为5.于是在页表中找到下标为1的页表项,通过这个页表项我们能找到一个唯一的页框。再在该页框中从找到第5个字节的地址。该地址就是0x0000 1005对应的物理地址。
在这里插入图片描述

二级页表

在二级页表中,最外层的页表我们当成一个页目录。页目录中的每一项都指向一张页表。一共有1024个页目录项,即一共有1024张页表,每一张页表有1024个页表项,刚好对应1024*1024个页框。
1.页目录大小计算:

  • 页目录项大小:4字节。
  • 页目录数量:1024.

页目录总大小:4byte*1024=4KB

2.每个页表的大小计算:

  • 页表项大小:4字节
  • 页表项数量:每一个页表都有1024个页表项

每个页表的大小:10244byte=4KB
页表的总大小:1024
4KB=4MB
二级页表的总大小:4MB+4KB约等于4MB

寻址过程

将虚拟地址分为三个部分:

  1. 页目录索引:高10位用来索引页目录项,10个二进制位最多表示1024个位置。
  2. 页表索引:中间10位索引页表项
  3. 页内偏移量:低12位用于表示页内偏移量,12个二进制位最多表示4096个位置,刚好对应页框内每个字节的相对位置。

当我们拿到一个虚拟地址,取出高10位的二进制表示的值,作为页目录的下标找到目标页表。再取出中间10位二进制表示的值,用来作为目标页表的下标,来找到目标页框。最后取出低12位,在目标页框中找到唯一一个字节地址。

假设现在有一个虚拟地址0x00001005,得到页目录索引为0,页表索引为1,页内偏移量为5.所以我们就去下标为0的页目录项种去找到页表,并在该页表下标为1的页表项中找到页框,最后在该页框中找到第5个字节的地址。
在这里插入图片描述

一级页表和二级页表的对比

尽管从理论上看,一级页表和二级页表的总空间成本差不多。但是二级页表的使用效率会更高。
如果采用一级页表,每个进程都需要分配整个页表的内存,也就意味着每个进程都需要有4MB的空间来存放页表,且页表项很多都是空的。这对大多数应用来说都是一种浪费。

如果采用二级页表或者三级页表。每个进程拥有一张页目录页表的数量会根据实际情况来进行分配,因此实际内存小于4MB。这样一来,避免了为进程分配大量未使用的页表,从而节省了内存
从时间效率上来看,虽然一级页表直接可以找到页框的地址,而多级页表需要经过多次索引,但是多级页表带来空间上的节省是值得多消耗一些索引时间的

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

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

相关文章

OrangePi AIpro测评:智能与创新的完美结合

OrangePi AIpro上手指南 简介 香橙派与华为合作发布的香橙派AiPro为Ai主力,为边缘设备的Ai计算提供了可能。 集成图形处理器,拥有8GB/16GB LPDDR4X(我这个是8G内存版本的),可以外接32GB/64GB/128GB/256GB eMMC模块&a…

【从零开始学习RabbitMQ | 第三篇】什么是延迟消息

目录 前言: 延迟消息: 延迟消息实现方式: 死信交换机: 延迟消息插件: 1.基于注解的方式 2.基于Bean的方式 总结: 前言: 在现代软件开发中,异步消息处理已成为构建可扩展、高可…

CR渲染噪点严重怎么办?常见噪点来源+排查方法

使用Corona渲染器进行渲染时,画面出现噪点是常见现象,尤其是在渲染初期。轻微的高频噪点通常是正常的,但如果经过多次渲染或长时间渲染后噪点依然明显,就可能意味着渲染设置或场景本身存在问题。虽然我们可以利用降噪功能模糊噪点…

5G专网驻网失败分析(suci无效)

suci 5G终端第一次驻网时,注册消息Registartion request中携带的5GS mobile identity要携带suci类型的mobile identity。 注册消息协议规范见5G NAS 协议3gpp TS24.501 8.2.6 Registration request。 suci协议规范参见3gpp TS24.501 9.11.3.4 5GS mobile identity …

iOS--工厂设计模式

iOS--工厂设计模式 设计模式的概念和意义类族模式UIButton作为类族模式的例子总结 三种工厂设计模式简单工厂模式(Simple Factory Pattern):代码实例 工厂方法模式(Factory Method Pattern):代码实例 抽象工…

【NumPy】全面解析NumPy的astype函数:高效数据类型转换指南

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

Python | Leetcode Python题解之第105题从前序与中序遍历序列构造二叉树

题目: 题解: class Solution:def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:if not preorder:return Noneroot TreeNode(preorder[0])stack [root]inorderIndex 0for i in range(1, len(preorder)):preorderVal pr…

接口性能测试复盘:解决JMeter超时问题的实践

在优化接口并重新投入市场后,我们面临着一项关键任务:确保其在高压环境下稳定运行。于是,我们启动了一轮针对该接口的性能压力测试,利用JMeter工具模拟高负载场景。然而,在测试进行约一分钟之后,频繁出现了…

前端 CSS 经典:水波进度样式

前言&#xff1a;简单实现水波进度样式&#xff0c;简单好看。 效果图&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" /><meta http-equiv"X-UA-Compatible" cont…

产线虚拟现实vr仿真软件开发在线上能全面呈现企业品质和专业度

在数字化浪潮中&#xff0c;上海VR全景场景制作公司凭借其领先的VR全景制作技术&#xff0c;正为各行各业带来前所未有的沉浸式体验。无论是学校企业场地的生动展示&#xff0c;还是汽车内饰与外观的360度全景呈现&#xff0c;我们都能通过VR虚拟现实制作技术&#xff0c;让您的…

双击移动硬盘打不开?原因分析与数据恢复全攻略

在日常生活和工作中&#xff0c;移动硬盘作为数据存储和传输的重要工具&#xff0c;扮演着至关重要的角色。然而&#xff0c;当我们遇到双击移动硬盘无法打开的情况时&#xff0c;往往会感到十分困扰。本文将详细探讨双击移动硬盘打不开的原因&#xff0c;并提供两种有效的数据…

(C语言) 泛型表达式

文章目录 ⭐语法⭐举例&#x1f6a9;判断对象类型&#x1f6a9;判断指针&#x1f6a9;函数重载&#x1f6a9;嵌套使用 END ⭐语法 Ref: 泛型选择 (C11 起) - cppreference.com 关键词&#xff1a; Genericdefault _Generic(控制表达式 , 关联列表) (C11 起) 关联列表 类型名:…

floodfill 算法(上)

目录 图像渲染 题意&#xff1a; 题解&#xff1a; 非递归&#xff1a; 递归&#xff1a; 岛屿数量 题解&#xff1a; 非递归&#xff1a; 递归&#xff1a; 岛屿的最大面积 题解&#xff1a; 非递归&#xff1a; 递归&#xff1a; 被围绕的区域 题解&#xff1a…

【加密与解密(第四版)】第十四章笔记

第十四章 漏洞分析技术 14.1 软件漏洞原理 缓冲区溢出漏洞&#xff1a;栈溢出 堆溢出、整型溢出&#xff08;存储溢出、计算溢出、符号问题&#xff09; UAF&#xff08;Use-After-Free&#xff09;漏洞 14.2 ShellCode 功能模块&#xff1a;下载执行、捆绑、反弹shell 14.3 …

采用java语言+B/S架构+后端SpringBoot前端Vue开发的ADR药品不良反应智能监测系统源码

采用java语言&#xff0b;B/S架构&#xff0b;后端SpringBoot前端Vue开发的ADR药品不良反应智能监测系统源码 ADR监测引擎每日主动获取检验数据、病历内容&#xff08;可拓展&#xff09;、以及其他临床数据&#xff0c;根据知识库内容自动判定患者是否有不良反应迹象&#xf…

kettle组件之java代码,快速上手必看

我们先了解不同于java代码的kettle的一些方法 1、getRow()&#xff1b; 获取每一行数据&#xff0c;循环读数据&#xff1b;返回的是Object[]数组 2、get(Fields.in,"字段名"); 获取具体的某个字段的名称 3、get(Fields.in,"字段名").getString(r); …

【软考】下篇 第15章 面向服务架构设计理论与实践

目录 一、SOA定义二、微服务微服务优势微服务与SOA对比微服务架构模式方案微服务设计约束 三、SOA参考架构四、SOA设计的标准要求五、SOA设计原则六、SOA设计模式七、SOA实施 一、SOA定义 面向服务的体系结构 (Service-Oriented Architecture,SOA), 从应用和原理的角度看&…

网络原理-HTTPS协议

在前面说到HTTP中,我们通过抓包,可以看到许多信息内容,其中往往会包含一些敏感信息,这些都是明文传输,当我们的请求被黑客或者不法分子截获后,那就很危险了,因此衍生出了HTTPS协议来对传输数据进行加密。 一、加密原理 基本原理如下&#xff1a; 明文 密钥 > 密文 密文…

线性稳压电路和开关稳压电路

稳压二极管稳压电路 电网电压增大&#xff0c;导到u1端的电压增大&#xff0c;从而使输出电压&#xff0c;稳压二极管两端的电压增大&#xff0c;稳压二极管两端电压增大&#xff0c;使流过的电注增大。那么&#xff0c;流过线性电阻R的总电流增大。 Ur电压增大&#xff0c;从…

网络故障排除—NAT-源进源出

多网络双出口一边是运营商A,一边是运营商B&#xff0c;将内网服务器分别映射到运营商B和运营商A出口。查了保证内部上网用户网速快管理员开启了运营商选路功能&#xff0c;运营商B的网站从运营商B出去&#xff0c;然后写有两条等价默认路由分别指向两个外网出口。营商A的网站从…