操作系统——内存管理——分段和分页

一、 物理地址和逻辑地址

物理地址:加载到内存地址寄存器中的地址,内存单元的真正地址。在前端总线上传输的内存地址都是物理内存地址,编号从0开始一直到可用物理内存的最高端。这些数字被北桥(Nortbridge chip)映射到实际的内存条上。物理地址是明确的、最终用在总线上的编号,不必转换,不必分页,也没有特权级检查(no translation, no paging, no privilege checks)。

逻辑地址:CPU所生成的地址。逻辑地址是内部和编程使用的、并不唯一。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址(偏移地址),不和绝对物理地址相干。

为什么会有这两种地址?

个人觉的原因在于逻辑地址分配更加灵活,可以允许不唯一,看起来也较为直观,例如,一段代码中分配数组,逻辑地址上是连续的,然而在物理地址上,这个数组所占用的页可能分散开来,物理地址上就是不连续的,这样对程序的可理解性上有影响。另外,有了逻辑地址这个概念,才能使用虚拟内存技术。

2、 Paging,分页内存管理方案

2.1 分页的最大作用就在于:使得进程的物理地址空间可以是非连续的。

物理内存被划分为一小块一小块,每块被称为帧(Frame)。分配内存时,帧是分配时的最小单位,最少也要给一帧。在逻辑内存中,与帧对应的概念就是页(Page)。

逻辑地址的表示方式是:前部分是页码后部分是页偏移。

例如,已知逻辑空间地址为2^m 个字节(也就是说逻辑地址的长度是m位) ,已知页大小是 2^n 字节。那么一共可以有2^(m-n)个页。因此页码部分会占m-n位,之后的n位,用来存储页偏移。

举个例子, 页大小为4B,而逻辑内存为32B(8页),逻辑地址0的页号为0,页号0对应帧5,因此逻辑地址映射为物理地址54+0=20。逻辑地址3映射物理地址54+3=23。逻辑地址13(4*3+1,页号为3,偏移为1,因此帧号为2),映射到物理地址9。

在这里插入图片描述

采用分页技术不会产生外部碎片(内存都被划分为帧),但可能产生内部碎片(帧已经是最小单元,因此帧内部可能有空间没有用到)。

按概率计算下来,每个进程平均可有半个帧大小的内部碎片。

2.2 页表的硬件实现

上一小节中写到页表是逻辑地址转化到物理地址的关键所在。那么页表如何存储?

每个操作系统都有自己的方法来保存页表。绝大多数都会为每个进程分配一个页表。现在由于页表都比较大,所以放在内存中(以往是放在一组专用寄存器里),其指针存在进程控制块(PCB)里,当进程被调度程序选中投入运行时,系统将其页表指针从进程控制块中取出并送入用户寄存器中。随后可以根据此首地址访问页表。

页表的存储方式是TBL(Translation look-aside buffer, 翻译后备缓冲器)+内存。TBL实际上是一组硬件缓冲所关联的快速内存。若没有TBL,操作系统需要两次内存访问来完成逻辑地址到物理地址的转换,访问页表算一次,在页表中查找算一次。TBL中存储页表中的一小部分条目,条目以键值对方式存储。

在这里插入图片描述

2.3 页表的数据结构

a.

今年是2013年,现有的笔记本电脑,内存地址空间一般为2^32 字节以上。对于具有32位逻辑地址空间的计算机系统,如果系统的页大小为4KB (2^12B) ,那么页表可以拥有2^(32-12)个,也就是一百多万个条目,假设每个条目占有4B,那每个进程都需要4MB的物理地址空间来存放页表本身。而且,页表本身需要分配在连续内存中。

为此,Hierarchical Paging(层次化分页)被提出,实际上就是将页号分为两部分,第一部分作为索引,第二部分作为页号的偏移。

以一个4kb页大小的32位系统为例。一个逻辑地址被分为20位的页码和12位的页偏移。因为要对页表进行再分页,所以该页号可分为10位的页码和10位的页偏移。这样一个逻辑地址就表示如下形式:

在这里插入图片描述

地址转换过程如下:

在这里插入图片描述

地址由外向内转换,因此此方法也被称为forward-mapped page table(向前映射表)。

b. Hashed Page Tables 哈希页表

处理超过32位地址空间的常用方法是使用hashed page table(哈希页表),并以虚拟页码作为哈希值。哈希页表的每一条目都包括一个链表的元素,这些元素哈希成同一位置。每个元素有三个域:虚拟页码,所映射的帧号,指向链表中下一个元素的指针。

个人看来,哈希页表的地址转换方式,实际上是Chaining(链接)方式,也就是一种哈希函数的溢出处理方式(另一种溢出处理方式叫做Open Addressing,开放寻址),具体过程如下:

逻辑地址需要大于32bit的地址空间来表示,但是操作系统仍只有32bit来表示地址。此时人们便想到虚拟页地址,虚拟地址可以在32bit表示范围之内,然后利用哈希函数完成逻辑地址到虚拟地址的映射,由于虚拟地址更少,哈希函数会出现溢出,这里使用Chaining来解决溢出。

逻辑地址中的页号(下图中的p)经过哈希函数的计算,算出虚拟地址中的页号,根据虚拟页号可以在哈希表中以O(1)方式寻址,用p与链表中的每一个元素的第一个域相比较。如果匹配,那么相应的帧号就用来形成物理地址。如果不匹配,就对链表中的下一个节点进行比较,以寻找一个匹配的页号。

在这里插入图片描述

c. Inverted page table 反向页表

时间关系,这段暂时略过。

三、 Segmentation,分段内存管理方案

采用分页内存管理有一个不可避免的问题:用户视角的内存和实际内存的分离。设想一段main函数代码,里面包含Sqrt函数的调用。按照编写者的理解,这段代码运行时,操作系统应该分配内存给:符号表(编译时使用),栈(存放局部变量与函数参数值),Sqrt代码段,主函数代码段等。这样,编写者就可以方便地指出:“函数sqrt内存模块的第五条指令”,来定位一个元素。而实际上,由于采用Paging的管理方式,所有的一切都只是散落在物理内存中的各个帧上,并不是以编写者的理解来划分模块。

在这里插入图片描述

Segmentation的内存管理方式可以支持这种思路。逻辑地址空间由一组段组成。每个段都有名字和长度。地址指定了段名称和段内偏移。因此用户通过两个量来指定地址:段名称和偏移。段是编号的,通过段号而非段名称来引用。因此逻辑地址由有序对构成:

<segment-number,offset>(<段号s, 段内偏移d>)

段偏移d因该在0和段界限之间,如果合法,那么就与基地址相加而得到所需字节在物理内存中的地址。因此段表是一组基地址和界限寄存器对。

在这里插入图片描述

例如下图,有5个段,编号0~4,例如段2为400B开始于位置4300,对段2第53字节的引用映射成位置4300+53=4353。而段0字节1222的引用则会触发地址错误,因为该段的仅为1000B长(界限为1000)。

在这里插入图片描述

4、 合并分段和分页的管理方案

在现有的Intel兼容计算机(x86)上,采用的内存管理方案是分段和分页合并的管理方案。

在这个方案中,逻辑地址,如前一节中所说,是由一个段标识符加上一个指定段内相对地址的偏移量,表示为 [段标识符:段内偏移量]。

这样的逻辑地址转换的过程是怎样呢?如下图所示:

在这里插入图片描述

当CPU要执行一条引用了内存地址的指令时,转换过程就开始了。第一步是把逻辑地址转换成线性地址。但是,为什么不跳过这一步,而让软件直接使用线性地址(或物理地址呢?)原因主要是因为:

(1) Intel的更新是渐进式而非革命式,新的处理器需要兼容和保留过往的设置。具体的原因,博文Memory Translation and Segmentation (http://blog.csdn.net/drshenlei/article/details/4261909) 中讲的较为清楚。

(2) 如上节所说,采用段内存管理,可以跟方便地进行地址保护(同一类型的地址逻辑地址在一起)。

下面讲逻辑地址到线性地址的部分。

在IBM OS/2 32位版本的操作系统,和Intel 386的环境下。操作系统采用的内存分配方式就是分段和分页合并的方式。

逻辑地址的实际上是一对<选择符,偏移>。

选择符的内容如下:
在这里插入图片描述

从左开始,13位是索引(或者称为段号),通过这个索引,可以定位到段描述符(segment descriptor),而段描述符是可以真正记载了有关一个段的位置和大小信息, 以及访问控制的状态信息。段描述符一般由8个字节组成。由于8B较大,而Intel为了保持向后兼容,将段寄存器仍然规定为16-bit(尽管每个段寄存器事实上有一个64-bit长的不可见部分,但对于程序员来说,段寄存器就是16-bit的),那么很明显,我们无法通过16-bit长度的段寄存器来直接引用64-bit的段描述符。因此在逻辑地址中,只用13bit记录其索引。而真正的段描述符,被放于数组之中。

这个内存中的数组就叫做GDT(Global Descriptor Table,全局描述表),Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址。程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。

除了GDT之外,还有LDT(Local Descriptor Table,本地描述表),但与GDT不同的是,LDT在系统中可以存在多个,每个进程可以拥有自己的LDT。LDT的内存地址在LDTR寄存器中。

在之前图中的TI位,就是用来表示此索引所指向的段描述符是存于全局描述表中,还是本地描述表中。=0,表示用GDT,=1表示用LDT。

RPL位,占2bit,是保护信息位,还没有仔细了解过这一块,暂时先不写。

找到,段描述符后,加上偏移量,便是线性地址。转换过程如下:

在这里插入图片描述

在Intel 386的环境下,线性地址转换为物理地址的过程,和第二节分页式内存管理中,层次分页中,逻辑地址转换为物理地址的方法类似。如下图。

在这里插入图片描述

Intel 80386的地址转换全过程如下图:

在这里插入图片描述

本文来自:https://www.cnblogs.com/felixfang/p/3420462.html

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

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

相关文章

Kubernetes攻略之新手上路

在公有云、私有云和混合云的环境中&#xff0c;Kubernetes已经成为规模化部署容器应用的事实标准。最大的公有云平台AWS、谷歌云、Azure、IBM云和Oracle云目前都提供Kubernetes的管理服务&#xff08;Managed Services&#xff09;。各大互联网公司也开始将服务部署到Kubernete…

操作系统——深入理解虚拟内存机制

本文来自&#xff1a;https://www.jianshu.com/p/13e337312651 概述 现代操作系统了提供了一种对主存的抽象概念&#xff0c;叫做虚拟内存。它为每个进程提供了一个非常大的&#xff0c;一致的和私有的地址空间。虚拟内存提供了以下的三个关键能力&#xff1a; 它为所有进程提…

dotNET Core 中怎样操作 AD?

做企业应用开发难免会跟 AD 打交道&#xff0c;在之前的 dotNET FrameWork 时代&#xff0c;通常使用 System.DirectoryServices 的相关类来操作 AD &#xff0c;在 dotNET Core 中没有这个命名空间&#xff0c;在张善友大佬的推荐下&#xff0c;知道了 Novell.Directory.Ldap。…

操作系统——页面置换算法

一、页面置换算法简介 操作系统将内存按照页的进行管理&#xff0c;在需要的时候才把进程相应的部分调入内存。当产生缺页中断时&#xff0c;需要选择一个页面写入。如果要换出的页面在内存中被修改过&#xff0c;变成了“脏”页面&#xff0c;那就需要先写会到磁盘。页面置换…

在树莓派4上安装 .NET Core 3.0 运行时及 SDK

点击上方蓝字关注“汪宇杰博客”导语我最近买了个树莓派4&#xff0c;4GB内存高富帅配置&#xff0c;并安装了官方操作系统Raspbian。今天我成功运行了一个ASP.NET Core 3.0 应用程序。我们来看看怎么弄的吧~ARM32 还是 ARM64?需要说明的是&#xff0c;目前无法在树莓派 4 上运…

.NET生成漂亮桌面背景

前言一天&#xff0c;我朋友指着某某付费软件对我说&#xff0c;这个东西不错&#xff0c;每天生成一张桌面背景&#xff0c;还能学英语&#xff08;放置名人名言和翻译&#xff09;&#xff01;我说&#xff0c;这东西搞不好我也能做&#xff0c;然后朋友说&#xff0c;“如果…

Mysql 执行流程

mysql执行一个查询的过程&#xff0c;到底做了些什么&#xff1a; 客户端发送一条查询给服务器&#xff1b;服务器先检查查询缓存&#xff0c;如果命中了缓存&#xff0c;则立刻返回存储在缓存中的结果。否则进入下一阶段。服务器段进行SQL解析、预处理&#xff0c;在优化器生成…

Autofac的AOP面向切面编程研究

我的理解是 把系统性的编程工作封装起来 》我给这个取个名字叫 “Aspect”&#xff0c;然后通过AOP技术把它切进我们的业务逻辑代码 》 “业务“这样的好处&#xff1a;“Aspect” 和 “业务” 相互独立&#xff0c;既可以让“业务” 用到了 “Aspect” 又让2者互相独立不耦合&…

计算机网络原理梳理丨清晰认识 TCP/IP 协议,图解秒懂!

作者&#xff1a;MobMsg&#xff0c;资深全端工程师一枚&#xff0c;架构师社区合伙人&#xff01;TCP/IP 协议族Internet 的核心协议就是 TCP/IP&#xff0c;广泛应用于局域网和广域网&#xff0c;目前已有20年发展史&#xff0c;是现用国际通行标准。TCP/IP 是个协议族&#…

MySQL 覆盖索引、最左前缀原则、索引下推

1、覆盖索引 1.1 概念 索引是高效找到行的一个方法&#xff0c;当能通过检索索引就可以读取想要的数据&#xff0c;那就不需要再到数据表中读取行了。如果一个索引包含了&#xff08;或覆盖了&#xff09;满足查询语句中字段与条件的数据就叫做覆盖索引。 1.2 判断标准 使用…

Entity Framework Core生成的存储过程在MySQL中需要进行处理及PMC中的常用命令

在使用Entity Framework Core生成MySQL数据库脚本&#xff0c;对于生成的存储过程&#xff0c;在执行的过程中出现错误&#xff0c;需要在存储过程前面添加delimiter //附&#xff1a;可以使用Visual Studio中的程序包管理器控制台执行Entity Framework Core中的迁移命令。PMC …

Exceptionless 5.0.0本地Docker快速部署介绍

在之前我有专门写两篇文章介绍过Exceptionless这款开源日志项目的使用和部署&#xff0c;但是当时是基于4.1.0版本&#xff08;2017年的release&#xff09;&#xff0c;时隔两年多Exceptionless也推出了5.0.0版本。&#xff08;1&#xff09;&#xff08;2&#xff09;01—关于…

数据库事务及隔离级别

一、事务的基本要素&#xff08;ACID&#xff09; 1、原子性&#xff08;Atomicity&#xff09;&#xff1a;事务开始后所有操作&#xff0c;要么全部做完&#xff0c;要么全部不做&#xff0c;不可能停滞在中间环节。事务执行过程中出错&#xff0c;会回滚到事务开始前的状态…

定了!10 月 8 日!Jupyter Notebook 原生支持将正式来到 VS Code!

北京时间 2019 年 9 月 21 日&#xff0c;在 PyCon China 2019 大会上&#xff0c;前不久&#xff0c;我们已经可以尽管如此&#xff0c;还是有许多童鞋来询问这个功能何时能正式发布。现在&#xff0c;我们可以在 VS Code Python 插件的 Release Plan 看到正式的发布时间已经确…

图解MySQL 内连接、左连接、右连接

一、准备工作 用两个表&#xff08;a_table、b_table&#xff09;&#xff0c;关联字段a_table.a_id和b_table.b_id来演示一下MySQL的内连接、外连接&#xff08; 左(外)连接、右(外)连接、全(外)连接&#xff09;。 MySQL版本&#xff1a;Server version: 5.6.31 MySQL Comm…

微软想将新版Edge浏览器引入Linux

继推出 WSL2、将 exFAT 技术添加至 Linux 内核&#xff0c;和宣布第一届微软 Linux 大会后&#xff0c;微软再次瞄准了 Linux。这次 Linux 用户将很可能迎来新版 Edge 浏览器。微软网络技术程序经理 Sean Larson 在 Twitter 上发布了一条消息&#xff0c;表示 Edge 开发团队正在…

一套代码同时支持.NET Framework和.NET Core

在.NET Core的迁移过程中&#xff0c;我们将原有的.NET Framework代码迁移到.NET Core。如果线上只有一个小型的应用还好&#xff0c;迁移升级完成后&#xff0c;只需要维护.NET Core这个版本的代码。但是&#xff0c;如果是一个大型分布式应用&#xff0c;几百台Server&#x…

从壹开始 [Admin] 之五 ║ 实现『按钮』级别权限配置

正文一、前情回顾哈喽大家好&#xff0c;在这个欢庆的日子里&#xff0c;老张祝大家工作都能蒸蒸日上&#xff01;今天正好也是社团成立的第一天&#xff0c;我也是希望今天能是个纪念日&#xff0c;沾沾这个大喜庆&#xff01;放假这两天&#xff0c;倒是学到了很多东西&#…

MySQL——binlog,redo log

一、什么是binlog、redo log binlog属于逻辑日志&#xff0c;是逻辑操作。innodb redo属于物理日志&#xff0c;是物理变更。逻辑日志有个缺点是难以并行&#xff0c;而物理日志可以比较好的并行操作。 binlog是MySQL Server层记录的日志&#xff0c; redo log是InnoDB存储引…

“自启动”树莓派上的 .NET Core 3.0 环境

点击上方蓝字关注“汪宇杰博客”导语昨天发了一篇《自动配置环境变量Rapbian 系统启动时会去执行 .profile 文件里的命令。因此我们只需要把配置环境变量的命令加入 .profile 文件即可。在 Linux 中&#xff0c;.profile 扩展用于终端程序中的文件。Linux 和 Mac OS X 终端程序…