5.2启动内存分页机制,畅游虚拟空间

news2025/7/8 9:05:57

5.2启动内存分页机制,畅游虚拟空间

即使机器上只有512MB的内存,每个进程自己的内存空间也是4GB,这4GB便是指的虚拟内存空间。下面就是讲解虚拟内存空间是怎么来的。

5.2.1内存为什么要分页

问题场景:由于多进程的发展,当内存固定时为了支持更多进程的运行,而传统的内存段基址:段内偏移是直接访问物理地址,而一段程序的地址是连续的这就导致了所需要的物理地址也是连续的。当内存中出现很多内存碎片的时候,总的空闲内存满足但是这些内存不满足连续,这就将导致进程无法加载。所有为了解决这个问题引出了内存分页机制。
下面是一个例子:
图54所示模拟了多个进程并行的情况。 在第1步中, 系统里有3个进程正在运行。 进程A、 B、 C各占了 10MB、 20MB、 30MB 的内存空间。 物理内存还是挺宽裕的,还剩下 15MB 可用。 到了第2步就悲催了。此时进程B 已经运行结束。 腾出了 20MB 的内存。 可是待加载运行的进程D需要20MB+3KB的内存空间, 即20483KB。 现在的运行环境未开启分页功能。 “段基址+段内偏移”产生的线性地址就是物理地址 ′程序中引用的线性地址是连续的 所以物理地址也连续。 虽然总共剩下 35MB 内存可用。可问题是明摆着的, 现在连续的内存块只有原来进程B 的20MB 和最下面可用内存 15MB。 哪一块都不够进程D用的这怎么办呢?
请添加图片描述
对于上面的解决方案有两个:
1.等待进程C运行完后腾出内存, 这样连续可用的内存就够运行进程D 了。
2.将进程A的段A3 或进程C的段 C1 换出到硬盘上。 腾出一部分空间。 加上邻接的 20MB. 足够容纳进程D。
针对第二种解决方案首先需要进行内存的换入换出:
内存是怎么换出的:
在保护模式下, 段描述符是内存段的身份i正。 CPU 在引用一个段时, 都要先查看段描述符。 很多时候,段描述符存在于描述符表中 (GDT或LDT), 但与此对应的段并不在内存中, 也就是说, CPU 允许在描述符表中已注册的段不在内存中存在,这就是它提供给软件使用的策略 我们利用它实现段式内存管理。 如果该描述符中的P位为1, 表示该段在内存中存在。 访问过该段后, CPU将段描述符中的A位置1, 表示近来刚访问过该段。相反, 如果P位为0, 说明内存中并不存在该段, 这时候CPU将会抛出个NP (段不存在) 异常, 转而去执行中断描述符表中NP异常对应的中断处理程序, 此中断处理程序是操作系统负责提供的, 该程序的工作是将相应的段从外存中载入到内存中, 并将段描述符的P位置1,中断处理函数结束后返回, CPU重复执行这个检查, 继续查看该段描述符的P位, 此时己经为1了, 在检查通过后,将段描述符的A位置1。
内存是怎么换出的:
段描述符的A位由 CPU置1, 但清0工作可是由操作系统来完成的。 此位干吗用的呢? 如果仅仅用来表示
该段被访问过, 这也意义不大啊。 其实这正是软件和硬件相互配合的体现,操作系统每发现该位为1后就将该位清0,这样一来, 在一个周期内统计该位为1 的次数就知道该段的使用频率了, 从而可以找出使用频率最低的段。当物理内存不足时, 可以将使用频率最低的段换出到硬盘以腾出内存空间给新的进程。 当段被换出至硬盘后,操作系统将该段描述符的P位置 0。 当下次这个进程上 CPU 运行后, 如果访问了这个段, 这样程序就回到了刚开始 CPU检查出P位为0、 紧接着抛出异常、 执行操作系统中断处理程序、 换入内存段的循环。
这样通过A位P位,中断处理程序,硬件,操作系统实现了内存换入和换出的循环。
第二个方法虽然解决了内存不足的问题, 但也有缺陷。 比如物理内存特别小, 无法容纳任何一个进程的
段, 这就没法运行进程了。 更没法做段的换入换出。
想一想, 出现这种问题的原因是什么? 问题的本质是在目前只分段的情况下, CPU 认为线性地址等于物理地址。 而线性地址是由编译器编译出来的, 它本身是连续的, 所以物理地址也必须要连续才行。 但我们可用的物理地址不连续 换句话说,如果线性地址连续 而物理地址可以不连续不就解决了吗。
按照这种思路,我们首先要做的是解除线性地址与物理地址一一对应的关系 然后将它们的关系重新建立。 通过某种映射关系 可以将线性地址映射到任意物理地址。这种映射关系是通过一张表来实现的,该表就是我们所说的页表,查找也表的工作是由硬件完成的。

5.2.2一级页表

保护模式下的分段机制:
在保护模式中段寄存器中的内容已经是选择子。 但选择子最终就是为了要找到段基士止, 其内存访
问的核心机制依然是 “段基址= 段内偏移地士止″, 这两个地址在相加之后才是绝对地址。 也就是我们所说
的线性地址, 此线性地址在分段机制下被 CPU 认为是物理地址。 直接拿来就能用, 也就是说, 此线性地
士止可以直接送上地址总线。 将段基址和段内偏移地址相加求和的工作是由 CPU 的段部件自动完成的。 整
个访问内存的过程如图 5_6所示。
请添加图片描述
保护模式下的分页机制:
分页机制要建立在图 5-6 所示分段机制的基础上, 也就是说, 段部件的工作依然免不了, 所以分页只能是在分段之后进行的, 其过程如图 5-7 所示。
图 5-7 说明, CPU 在不打开分页机制的情况下,是按照默认的分段方式进行的段基址和段内偏移地址经过段部件处理后所输出的线性地址, CPU 就认为是物理地址。如果打开了分页机制, 段部件输出的线性地址就不再等同于物理地址了。 我们称之为虚拟地址, 它是逻辑上的, 是假的, 不应该被送上地址总线 (因为地址只是个数字, 任何数字都可以当作地址, 这里说的 “不应该″ 是指应该人为保证送上地址总线上的数字是正确的地址)CPU必须要拿到物理地址才行, 此虚拟地址对应的物理地址需要在页表中查找, 这项查找工作是由页部件自动完成的。 为了要搞清楚页部件的工作原理, 必须要搞清楚这两件事
1.分页机制的原理
2.页表的结构

请添加图片描述
分页机制的思想是: 通过映射, 可以使连续的线性地址与任意物理内存地址相关联, 逻辑上连续的线性地址其对应的物理地址可以不连续。
分页机制的作用有两方面。
1.将线性地址转换成物理地址。
2.用大小相等的页代替大小不等的段。这两方面的作用
请添加图片描述
由于有了线性地址到真实物理地址的这层映射经过段部件输出的线性地址便有了另外一个名字,虚拟地址。
下面根据上图介绍一下操作系统在分页机制下加载进程的过程。
图5-8 表示的是一个进程的地址转换过程, 从线性空间到虚拟空间再到物理地址空间, 每个空间大小都是 4GB。 图上的 4GB 物理地址空间属于所有进程包括操作系统在内的共享资源, 其中标注为已分配页的内存块被分配给了其他迸程, 当前进程只能使用未分配页。 此转换过程对任意一个进程都是一样的, 也就是说, 每个进程都有自己的 4GB 虚拟空间。
前面说过啦, 分页机制建立在分段机制之上, 与其脱离不了干系, 即使在分页机制下的进程也要先经过逻辑上的分段才行,每加载一个进程, 操作系统按照进程中各段的起始范围, 在进程自己的 4GB 虚拟地址空间中寻找可用空间分配内存段, 此虚拟地址空间可以是页表。也可以是操作系统维护的某种数掂结构总之此阶段的分配是逻辑上的,并没有真正写入物理内存。在分页机制下,分配情况如图 5-8 中所示的虚拟地址空间中的代码段和数据段。代码段和数据段在逻辑上被拆分成以页为单位的小内存块。 这时的虚拟地址虚如其名, 不能存放在任何数据。 接着操作系统开始为这些虚拟内存页分配真实的物理内存页, 它查找物理内存中可用的页, 然后在页表中
登记这些物理页地址。 这样就完成了虚拟页到物理页的映射, 每个进程都以为自己独享4GB地址空间。
对于从虚拟地址空间到物理地址空间的映射关系保存在页表中。页表就是个N行 1 列的表格页表中的每一行 (只有一个单元格) 称为页表项 (PageTableEntry,
PTE), 其大小是 4 字节, 页表项的作用是存储内存物理地址。 当访问一个线性地址时, 实际上就是在访问页表项中所记录的物理内存地址。
下图是映射方案原理:
请添加图片描述
下图是针对上面映射方案,为了使得页表不会占据太大的内存下图是选择合适的内存块大小:
请添加图片描述
官方中的内存块大小就是如图所示的情况,每个内存块大小是4KB,一种有1M的内存块,即也就是有1M的页表项。
上面所说的也就是一级页表:
请添加图片描述
针对如何寻找到正确的地址,可以利用5-10理解。右边第11-0位用来表示页的大小,也就是这12位可以作为页内寻址。左边第31-12位用来表示页的数量,同样这20位也用来索引一个页,可以来找到第几页的情况。
任意一个地址最终会落到某一个物理页中。 32 位地址空间共有 1M (1048756)
个物理页, 首先要做的是定位到某个具体物理页, 然后给出物理页内的偏移量就可以访问到任意1字节的内存啦。 所以用20 位二进制就可以表示全部物理页啦。 标准页都是4KB, 12 位二进制便可以表达4KB之内的任意地址。
在32位保护模式下虚拟地址的高20 位可用来定位一个物理页, 低 12 位可用来在该物理页内寻址。 这是如何实现的呢? 物理地址写在页表的页表项中, 段部件输出的只是线性地址, 所以问题就变成了:怎样用线性地址找到页表中对应的页表项。
在转换之前需要提前知道这两件事情:
1:分页机制打开前要将页表地址加载到控制寄存器 CR3 中, 这是启用分页机制的先决条件之一, 在介绍二级页表时会细说。 所以, 在打开分页机制前加载到寄存器 cr3 中的是页表的物理地址,页表中页表项的地址自然也是物理地址了。
2:虽然内存分页机制的作用是将虚拟地址转换成物理地址, 但其转换过程相当于在关闭分页机制下进行, 过程中所涉及到的页表及页表项的寻址, 它们的地址都被 CPU 当作最终的物理地址 (本来也是物理地址) 直接送上地址总线, 不会被分页机制再次转换 (否则会递归转换下去〉。
地址转换过程原理如下:
一个页表项对应一个页, 所以, 用线性地址的高 20 位作为页表项的索引每个页表项要占用 4字节大小, 所以这高 20 位的索引乘以4后才是该页表项相对于页表物理地址的字节偏移量。 用 cr3 寄存器中的页表物理地址加上此偏移量便是该页表项的物理地址, 从该页表项中得到映射的物理页地址, 然后用线性地址的低 12 位与该物理页地址相加所得的地址之和便是最终要访问的物理地址。
上面从虚拟地址到物理地址的过程通过页部件来计算:
页部件的工作:用线性地址的高20位在页表中索引页表项,用线性地址的低12位与页表项中的物理地址相加,所求的和便是最终线性地址对应的物理地址。
请添加图片描述
假设咱们是在平坦模型下工作, 不管段选择子值是多少, 其所指向的段基址都是 0, 指令 mov ax,[0xl234]中的 0x1234 称为有效地址, 它作为 “段基址= 段内偏移地址″ 中的段内偏移地址。 这样段基址为 0, 段内偏移地址为 0x1234. 经过段部件处理后, 输出的线性地址是 0x1234。由于咱们是演示分页机制, 必须假定系统己经打开了分页机制, 所以线性地址0x1234被送入了页部件。 页部件分析 0x1234的高20 位, 用十六进制表示高 20 位是 0x00001。 将此项作为页表项索引, 再将该索引乘以4后加上 cr3 寄存器中页表的物理地址, 这样便得到索引所指代的页表项的物理地址, 从该物理地址处 (页表项中〉 读取所映射的物理页地址= 0x9000。 线性地址的低 12 位是 0x234, 它作为物理页的页内偏移地址与物理页地址0x9000 相加, 和为 0x9234这就是线性地址 0X1234 最终转换成的物理地址。

二级页表

问题引出:为什么有了一级页表为什么还要搞二级页表?
(1) 一级页表中最多可容纳 1M (1048576) 个页表项每个页表项是4字节, 如果页表项全满的话便是4MB大小
(2) 一级页表中所有页表项必须要提前建好, 原因是操作系统要占用 4GB 虚拟地址空间的高1GB,挪用户进程要占用低 3GB。
(3) 每个进程都有自己的页表, 进程一多, 光是页表占用的空间就很可观了。
归根结底,我们要解决的是不要一次性地将全部页表项建好需要时动态创建页表项。如何解决呢?
什么是二级页表?
无论是几级页表, 标准页的尺寸都是4KB, 这一点是不变的。 所以 4GB 线性地址空间最多有1M个标准页。 一级页表是将这 1M个标准页放置到一张页表中, 二级页表是将这 1M 个标准页平均放置lK个 页表中。 每个页表中包含有 1K个页表项。 页表项是4字节大小, 页表包含1K个页表项, 故页表大小为 4KB, 这恰恰是一个标准页的大小。
拆分出了这么多个页表, 如何使用它们昵? 为此,专门有个页目录表来存储这些页表。 每个页表的物理地址在页目录表中都以页目录项 (PageDirectoryEntry,PDE) 的形式存储, 页目录项大小同页表项一 样, 都用来描述一个物理页的物理地址, 其大小都是4字节, 而且最多有 1024 个页表所以页目录表也是4KB大小,同样也是标准页的大小。页表是用于管理内存的数据结构, 其也要占用内存, 所以页目录表和页表所占用的物理页, 同样混迹 于物理内存之中, 如图5-13所示
请添加图片描述

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

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

相关文章

软考 - 计算机组成与结构

数据计算 数据的进制转化 十六进制符号 0X 或 H,可表示为0x18F 或 18FH m进制转n进制:先将m进制转化为十进制数,再将十进制数转化为n进制数(2进制可直接转8进制(3位)和16进制(4位&#xff09…

Python如何自动操作电脑桌面应用程序

前言 本文是该专栏的第2篇,后面会持续分享python的各种黑科技知识,值得关注。 熟悉python的朋友,都知道python可以做自动化,比如说selenium,pyppeteer,airtest等等。 但你是否听说过python可以来自动操作电脑桌面的应用程序呢,趟若临时接到某个需求,让你用python脚本…

基于zynq7100的OV5640摄像头照相机实验,提供工程源码和技术支持

目录1.设计架构2.工程简介3.zynq配置4.sd卡文件系统FATFS配置5.sd卡文件系统FATFS读写测试6.OV5640摄像头显示测试7.OV5640摄像头循环拍照测试8.OV5640摄像头按键拍照测试9.上板调试10.福利领取1.设计架构 设计框图如下: 采用Xilinx官方推荐的VDMA架构实现图像缓存…

TiDB丨一次TiDB GC阻塞引发的“惨案”......

前不久,从项目一线同学得到某集群的告警信息,某个时间段 TiDB duration 突然异常升高,持续时间6小时左右,需要定位到具体原因。 于是乎,我们就来一场关于TiDB GC阻塞的排查...... 分析过程 第一招 初步判断 既然…

Docker+nginx在CVM的机器远程发布hellogin

有两种方式,一种通过docker容器安装,一种是直接安装, 这里我们通过docker服务安装 常用操作 images是查询当前机器上所有的镜像有哪些 docker images删除镜像 docker rmi [MAGE ID ]可以查当前运行中的容器 docker ps -a开始/停止/删除容器 docker…

动态树的最值

一 问题描述 一棵树有 N 个节点,每个节点都有一个权值 Wi ,有 4 种操作。 ① 1 x y ,在两个节点 x、y 之间添加一条新边。因此,在这种操作之后,两棵树将连接成一棵新树。 ② 2 x y ,在树集合中找到包含节…

LeetCOde-剑指46-把数字翻译成字符串

1、动态规划法 我们通过观察可以发现,假如我们使用数组dp[i]dp[i]dp[i]来记录前iii位可能构成的字符串个数:1、当新加入的第i1i1i1位和第iii位能够构成一个大于9小于26的数字时,dp[i1]dp[i]dp[i−1]dp[i1]dp[i]dp[i-1]dp[i1]dp[i]dp[i−1]&a…

容器化部署(k8s)任务调度平台xxl-job(部署过程及踩坑问题记录)

文章预览:1 部署过程(下方ip代表服务器的ip哈)1.1 制作服务打包镜像DockerFile1.2 制作执行脚本run.sh1.3 jar包上上传1.4 kuboard创建----配置信息2 踩坑问题记录2.1 日志抛出异常2.2 原因分析2.3 过程分析及解决2.4 执行调度测试导入sql等过…

Baklib|SaaS产品,实现企业流程数字化

正如许多科技潮流一样,“SaaS”这个词也逐渐成为企业经理们谈论的话题。然而,如果您对“SaaS”一无所知,您可能会感到困惑并容易忽略它。那么,什么是“SaaS”?它的优点是什么?它如何帮助企业实现数字化转型…

SSM+VUE+ElementUI实现宠物领养系统,期末大作业

SSMVUEElementUI实现宠物领养系统 系统角色 领养人,管理员 系统功能 本系统的功能主要分为四大模块: 领养人用户模块:注册、领养人登录、申请领养、查看小动物信息、发布留言领养机构员工用户模块:领养机构员工登录、增加小动…

地平线开发者社区真心话大冒险,邀你闯关!

Hello! 各位初次见面的萌新和久经沙场的社牛 目前开发者社区已成立两年有余 感谢大家一路上的支持和理解 今天,我们也准备了一些小礼品 希望倾听大家作为用户和开发者的真心话 同时,也欢迎初次见面的萌新们一同冒险 期待陪伴大家走过更…

Protect Privacy from Gradient Leakage Attack in Federated Learning

wangjunxiao/GradDefense: Defense against Gradient Leakage Attack (github.com) Summary 针对DGA和DIA攻击,提出了一个轻量、保证训练准确性、够用的的防御机制。防御机制主要包括随机layer添加扰动,然后进行梯度补偿来减少噪声对模型准确性的影响。…

CORS处理跨域问题

“前后端分离的项目必然会遇到一个典型的问题——跨域问题。” 跨域 要解决跨域问题,首先得知道什么是跨域? 首先,跨域是访问的域名或IP、端口三者有一不同都属于跨域。(注意请求路径不是),即使在本地测试&…

【计算机网络】学习笔记--第一章

【计算机网络】学习笔记--第一章基本概念端系统之间的通信客户-服务器方式(C/S方式)对等连接方式:三种交换方式电路交换(Circuit Switching)分组交换(Packet Switching)报文交换(Mes…

centos7 安装与卸载 Mysql 5.7.27(详细完整教程)

目录 卸载 安装 卸载 1、关闭MySQL服务 systemctl stop mysqld2、使用 rpm 命令查看已安装的安装包 [nameVM-20-12-centos mysql1]$ rpm -qa|grep mysql 3、使用yum卸载安装的mysql [nameVM-20-12-centos mysql1]$ sudo yum remove mysql mysql-server mysql-libs mysql…

【LeetCode每日一题:775.全局倒置与局部倒置~~~维护前缀最大值】

题目描述 给你一个长度为 n 的整数数组 nums &#xff0c;表示由范围 [0, n - 1] 内所有整数组成的一个排列。 全局倒置 的数目等于满足下述条件不同下标对 (i, j) 的数目&#xff1a; 0 < i < j < n nums[i] > nums[j] 局部倒置 的数目等于满足下述条件的下标 …

Air780E连接点灯科技-LuatOS

前面发了腾讯云点灯以后&#xff0c;有朋友提到了点灯科技&#xff0c;人家都叫点灯科技了&#xff0c;那咱们学点灯必须连一下试试呀。本文将记录如何将设备连接点灯云平台&#xff0c;并通过手机进行远程控制 先上成果演示 一、点灯云准备 下载点灯科技的app-blinker&#…

Offsets 获取该行的起始索引 start=offsets (x)

获取数据列的第 x 行&#xff0c;通过 Offsets 获取该行的起始索引 startoffsets (x) 和下一行的起始索引 endoffsets (x1)&#xff0c;然后使用这两个索引通过 Bytes 获取具体数据对应的字节流 bytes.slice (start,end)&#xff0c;最后按照字段类型做相应的转换即可。 注&am…

QGC二次开发基础

文章目录 前言一、添加文件到QGC工程二、添加界面三、QML和C++交互四、信号与槽五、测试前言 QGC 4.2.4 一、添加文件到QGC工程 在qgroundcontrol/src目录下创建SimpleTest文件夹 在文件夹中创建SimpleTest.cpp、SimpleTest.h和SimpleTest.qml三个文件 在qgroundcontrol.p…

锁竞争导致的慢sql分析

线上在同步用户时&#xff0c;经常出现简单sql的慢日志。根据方法找到代码&#xff0c;发现方法内使用redisson进行锁操作&#xff0c;waiTime和leaseTime都为3秒,数据库操作比较简单&#xff0c;只是一个简单的用户更新操作。代码简化后如下 Override Transactional(rollback…