专栏首页飞天小牛肉你看到的所有地址都不是真的

你看到的所有地址都不是真的

先解释下一个困扰了我很久的问题:虚拟地址(vitural address)和逻辑地址(logical address)的区别。

大部分操作系统的书籍要么写的是虚拟地址,要么写的是逻辑地址,看的我一脸懵逼。

在《深入理解 Linux 内核》这本书中终于找到了确切的答案,这里我就不写出来了,扣概念的话这俩确实是有些区别的,不过对于我们日常使用以及理解操作系统来说的话,暂且可以把虚拟地址和逻辑地址理解为同一个意思

你看到的所有地址都不是真的

下面这段 C 代码摘录自《操作系统导论 - [美] 雷姆兹·H.阿帕希杜塞尔》,依次打印出 main 函数的地址,由 malloc(类似于 Java 中的 new 操作)返回的堆空间分配的值,以及栈上一个整数的地址:

得到以下输出:

我们需要知道的是,所有这些打印出来的地址都是虚拟的,在物理内存中这些地址并不真实存在,它们最终都将由操作系统和 CPU 硬件翻译成真正的物理地址,然后才能从真实的物理位置获取该地址的值。

OK,上述就当作一个引子,让各位对物理地址和虚拟地址有个直观的理解,下面正文开始。

物理寻址 Physical Addressing

物理地址的概念很好理解,你可以把它称为真正的地址。《深入理解计算机系统 - 第 3 版》中给出的物理地址(physical address)的定义如下:

计算机系统的主存被组织成一个由 M 个连续的字节大小的单元组成的数组。每字节都有一个唯一的物理地址。

比如说,第一个字节的物理地址是 0,接下来的字节地址是 1,再下一个是 2,以此类推,给定这种简单的结构,CPU 访问内存的最自然的方式就是使用这样的物理地址。我们把这种方式称为物理寻址(physical addressing)。

举个例子,比如说当程序执行了一条加载指令,指令内容是从物理地址 4 中读取 4 字节字传送到某个寄存器中。

物理寻址过程如下:当 CPU 执行到这条指令时,会生成物理地址 4,然后通过内存主线,把它传递给内存,内存取出从物理地址 4 处开始的 4 字节字,并将它返回给 CPU,CPU 会将它存放到指定的寄存器中。看下图:

其实不难发现,物理寻址这种方式,每一个程序都直接访问物理内存,其实是存在重大缺陷的:

1)首先,用户程序可以寻址内存的任意一个字节,它们就可以很容易地破坏操作系统,从而使系统慢慢地停止运行。

2)再次,这种寻址方式使得操作系统中同时运行两个或以上的程序几乎是不可能的

举个例子,我们打开了三个相同的程序(计算器),都执行到某一步。比方说,用户在这三个程序的界面上分别输入了 10、100、1000,其对应的指令就是把用户输入的数字保存在内存中的某个地址中。如果这个位置只能保存一个数,那应该保存哪个呢?这不就冲突了吗?

再举个例子,摘自《现代操作系统 - 第 3 版》:

一个程序给物理内存地址 1000 赋值也就是存入了一些数据后,另一个程序也同样给这个地址赋值,那么第二个程序的赋值会覆盖掉第一个程序所赋的值,这会造成两个程序同时崩溃。

当然了,我们也说了是几乎不可能,不是完全不可能,还是有一些方法可以在物理寻址这种方式下实现多个程序并发运行的。

最简单的方法就是:首先,将空闲的进程存储在磁盘上,这样当它们不运行时就不会占用内存,然后,让一个程序(或者说进程)单独占用全部内存运行一小段时间,当发生上下文切换的时候,就停止这个进程,并将它所有的状态信息保存在磁盘上,再加载其他进程的状态信息,然后运行一段时间...... 只要在某一个时间内存中只有一个程序,那么就不会发生上述所说的地址冲突。这就实现了一种比较粗糙的并发。

为什么说他是粗糙的呢,因为这种方法有一个问题:将全部的内存信息保存到磁盘太慢了!特别是当内存增长的时候。

因此,我们考虑把进程对应的内存一直留在物理内存中,在发生上下文切换的时候就切换到特定的区域。

如下图所示,有 3 个进程(A、B、C),每个进程拥有从 512KB 物理内存中切出来给它们的一小部分内存,可以理解为这 3 个进程共享物理内存:

显然,这种方式是存在一定安全隐患的。毕竟如果各个进程之间可以随意读取、写入内容的话那就乱套了。

那么如何对每个进程使用的地址进行保护(protection)呢?继续使用物理内存模型肯定是不行了,因此操作系统创造了一个新的内存抽象,引入了一个新的内存模型,那就是虚拟地址空间,很多书中都会直接称呼为 “地址空间(Address Space)”。

虚拟寻址 Virtual Addressing

我先通俗地解释下虚拟地址空间和虚拟地址的概念,直接上书中的定义读起来有点生涩。

就是说每个进程的栈啊、堆啊、代码段啊等等它们的实际物理内存地址对于这个进程来说是不可见的,谁也不能直接访问这个物理地址。

那我们怎么去访问这个进程呢?

操作系统会给每个进程分配一个虚拟地址空间(vitural address),每个进程包含的栈、堆、代码段这些都会从这个地址空间中被分配一个地址,这个地址就被称为虚拟地址。底层指令写入的地址也是虚拟地址。

每个进程都拥有一个自己的地址空间,并且独立于其他进程的地址空间。也就是说一个进程中的虚拟地址 28 所对应的物理地址与另一个进程中的虚拟地址 28 所对应的物理地址是不同的,这样就不会发生冲突了。

可以这么理解,物理地址就是一个仓库,虚拟地址就是一个门牌,比方说一共有三十个门牌,那么所有的进程都能看见这三十个门牌,但是他们看见的某个相同门牌,指向的并不是同一个仓库。

OK,下面再来看《现代操作系统 - 第 3 版》书中对于地址空间的解释,应该很容易理解了:

地址空间是一个进程可用于寻址内存的一套地址集合。每个进程都有一个自己的地址空间,并且这个地址空间独立于其他进程的地址空间(除了在一些特殊情况下进程需要共享它们的地址空间外)。 地址空间的概念非常通用,并且在很多场合中出现。比如电话号码,在美国和很多其他国家,一个本地电话号码通常是一个 7 位的数字。因此,电话号码的地址空间是从 0 000 000 到 9 999 999。 地址空间也可以是非数字的,以 “.com” 结尾的网络域名的集合也是地址空间。这个地址空间是由所有包含 2~63 个字符并且后面跟着 “.com” 的字符串组成的,组成这些字符串的字符可以是字母、数字和连字符。 到现在你应该已经明白地址空间的概念了,它是很简单的。

有了虚拟地址空间后,CPU 就可以通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到内存之前会先被转换成合适的物理地址,这个虚拟地址到物理地址的转换过程称为 地址翻译/地址转换(address translation)。

地址翻译需要 CPU 硬件和操作系统的密切合作:CPU 上的内存管理单元(Memory Management Unit,MMU)就是专门用来进行虚拟地址到物理地址的转换的,不过 MMU 需要借助存放在内存中的查询表,而这张表的内容正是由操作系统进行管理的。

那么,上述这一套 CPU 生成虚拟地址并进行地址翻译的流程就是虚拟寻址(virtual addressing)。举个例子,看下图:

References

  • 《操作系统导论 - [美] 雷姆兹·H.阿帕希杜塞尔》
  • 《现代操作系统 - 第 3 版》
  • 《深入理解计算机系统 - 第 3 版》

本文分享自微信公众号 - 飞天小牛肉(CS-Wiki),作者:飞天小牛肉

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-05-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 睁大眼睛看!不是所有交易所的币都能买!

    如今,数字资产的种类和影响力与日俱增。数字资产的公允价格形成、不同数字资产间的兑换交易,以及相关的客户服务、监管合规,甚至是衍生品交易的需求愈发强烈,每天新交易...

    区块链领域
  • 你看到的地图是这个世界的真实面目吗?

    在数据可视化中,除了常见的折线图条形图,还有一种很常见的图示,那就是地图。今天呢,我们就说说地图中的那些门道。

    卤代烃
  • 你买不到的酒,黄牛都有

    某白酒品牌的"黑市成交价"又双叒叕涨了。 几个月前还能用2000块钱拿下的一瓶酒,如今已经涨破了2400元大关。一方面,官方渠道上明码标价1000多元的价格常...

    腾讯防水墙
  • 你买不到的酒,黄牛都有

    某白酒品牌的"黑市成交价"又双叒叕涨了。 几个月前还能用2000块钱拿下的一瓶酒,如今已经涨破了2400元大关。一方面,官方渠道上明码标价1000多元的价格常...

    腾讯大讲堂
  • 查看 网关 及 局域网中的所有设备 IP地址

      假设上一步查到的网关IP是192.168.1.1。查看当前有多少设备已连接上我们的局域网:

    JNingWei
  • 数据迷思:你看到的事实,不一定是真相

    世间有无数事实。事实本身没有问题,然而一个事物可能有不同的事实侧面,呈现在你面前角度不同会塑造你对事物的不同看法;即使相同的侧面,不同的展现方式也会影响你对现实...

    wujunmin
  • 百万锁仓都没有,你真的真的真的是来认真写作的吗?

    最近一直在劝币乎写作的朋友买KEY锁仓,结果买了没多久,KEY大涨50%,打电话给我讲好开心。

    凌帅出口
  • 08 测试数据:是不是可以把所有的参数都保存到Excel中?

    将数据存储到一种数据存储文件中,这样 代码就可以自行查找对应的参数,然后调取测试框架执行测试流程,接着再通过自动比对返 回预期,检验测试结果是否正确。

    flowerdrop
  • [教程]让你拥有一个别人都看不到的隐私文件夹

    Youngxj
  • 并不是所有的 Github 写在简历上都加分

    很多招聘描述上面都会备注 github加分项,那么为什么它是加分项呢? 停,如果看到这里你还不知道 Github 是什么,可以看一下 Phodal的手记 htt...

    乔戈里
  • 关于debug你可能还不知道的技巧,建议所有人都看一下

    debug主要用来追踪代码的运行流程,从而分析定位异常发生的位置,以及在运行过程中参数的变化。也可以用debug模式来跟踪代码的运行流程去学习三方框架的源码。

    一条coding
  • 为啥不是所有的 Github 写在简历上都加分?

    很多招聘描述上面都会备注 github加分项,那么为什么它是加分项呢? 停,如果看到这里你还不知道 Github 是什么,可以看一下 Phodal的手记 htt...

    格姗知识圈
  • 光有热情不够,不是所有的中国制造业都能工业4.0

    >>>> 工业4.0要量力而行 中国制造业不缺少学习工业4.0的热情。在德国汉诺威工业博览会上,前去观展的中国企业家一年比一年多,不少人抱着“我这次去德国引进一...

    钱塘数据
  • 你看到的可能是假的奥巴马?没错,还真是假的!

    大数据文摘
  • 如何使用IPinfoga仅根据IP地址查询到你所在的位置

    IPinfoga是一款功能强大的OSINT公开资源情报工具,该工具可以导出关于目标IP地址的相关信息,比如说包含国家、城市和经纬度的地理位置信息等等。

    知识与交流
  • 跳出来看看,技术真的不是你一辈子的金饭碗

    原本不想在工作日分享给大家这篇毒鸡汤,可里面的很多观念和想法,确实刺激到了场主,或者也能说到正在看这篇文章的你吧。

    养码场
  • Spark的HistoryServer不能查看到所有历史作业分析

    Spark的HistoryServer能正常查看之前的历史作业日志,但新提交的作业在执行完成后未能在HistoryServer页面查看。

    Fayson
  • 你真的会用索引吗?来看看COUNT(*)到底能有多快

    作者简介 ? 案例说明 一个大表的COUNT,究竟能有多快?除类似物化视图的做法,我们所能做到的极限能有多快?这不是一个真实的案例,而是根据笔者在网上发的一篇帖...

    数据和云
  • 当@Transactional遇到@CacheEvict,你的代码是不是有bug!

    如上图所示,当@Transactional 遇到@CacheEvict,缓存放在 redis 中,这样写代码会有什么问题呢?你们的程序中是否写着这样的代码呢?如...

    用户1516716

扫码关注云+社区

领取腾讯云代金券