什么是内存(二):虚拟内存

参考文章:https://www.cnblogs.com/yaoxiaowen/p/7805964.html

问题:
1, 进程是,一个程序在运行时,会有这样一种假象,该程序(也就是这个进程)好像是独占使用 CPU 和内存,CPU 是没有间断地一条接一条的执行该程序的指令,所有的内存空间都是供该进程的代码和数据分配使用的。这是如何做到的。

  1. 不同进程之间,如果都同时使用一个内存地址,那么为什么没有引起冲突和错误

  2. 在程序运行时,库代码也要被加到内存中,如果许多程序都应用了这个库,那么内存中需要对库代码加载好多份吗?如果不是的,那么库代码又如何被所有进程所共享?

一 物理和虚拟寻址

1.1 物理寻址

在访问者看来,内存就是一个有M个字节大小的单元组成的数组,每个字节都有唯一的物理地址(Physical Address PA)。它的访问地址和数组一样,第一个地址都是0,后面的地址依次为 1,2,3 .... M-1, 这叫做线性地址空间。这种自然的寻址方式我们称之为物理寻址(physical addressing)。

注意:在访问内存时,对于任意一个地址,不管是(第0个还是第M-1个),访问该地址的时间总是相同的。

在各种数据结构中,我们都说 hash 表是最快的,比红黑树都要快,为啥 hash 最快?hash 表内部本质是永乐数组,所以本质上还是数组最快。为什么数组最快?这是因为知道数组的起始地址以及某个元素的序号,就可以得到该元素在内存中的地址,而对内存,访问任意一个地址,访问时间总是相同的。而类似链表、数等结构,却只能靠遍历了。


pysicalAddressing.png

上图是一个物理寻址的例子,这是一条加载指令,它读取从物理地址5开始的3个字节,CPU通过内存总线将指令和地址传给内存,内存读取从物理地址5开始的3个字节,返回给CPU。

1.2 虚拟寻址

virtualAddress.png

早期计算机使用物理寻址方式,但是到了现在的多任务计算机时代,普遍使用的是虚拟寻址(virtual Address)

CPU 通过一个虚拟地址(virtual address, VA)来访问内存,这个虚拟地址在被送到内存之前会先转换成一个物理地址,将虚拟地址转化成物理地址的任务叫做地址翻译(address translation)

有少数现代计算机系统依旧采用物理寻址方式,比如嵌入式、超级计算机。这些系统主要是执行单一任务,不像通用计算机那样使用多任务。可以想象到,物理寻址方式更快。这个道理,和Java比C++ 慢是一个道理。(虚拟机 / C++)

之所以不会发生文章开头的问题,正式因为虚拟内存的存在。

进程地址空间

virtual.png

上图是一个 64位 的进程地址空间,编译器在编译程序时,将结果编译 32/64 位的地址空间。虚拟寻址方式简化了编译器,链接器的工作。
同时也因为虚拟内存,每个进程才能有很大的,一致的,私有的地址空间。这方便了内存管理,保护了每个进程的地址空间不被其他进程破坏,同时也方便了共享库。

三、虚拟内存也是一种缓存思想

虚拟内存将内存看成是一个磁盘的高速缓存,内存中只保存活动区域,并根据需要在磁盘和内存之间来回传递数据。

从概念上说,虚拟内存被组织成一个由存放在磁盘上的 N 个连续的字节大小的单元组成的数组,也就是字节数组。
每个字节都有一个唯一的虚拟地址作为数组的索引。虚拟内存的地址和磁盘的地址之间建立映射关系。磁盘上活动的数组内容被缓存在主存中,在存储器层次中,磁盘(较低层L5)的数据被分割为块(block),这些块作为和内存(较高层,L4)之间的传输单元。内存作为虚拟内存(或者说磁盘)的缓存。

虚拟内存(VM)系统将虚拟内存分割为大小固定的虚拟页(Virtual Page),每个虚拟页的大小为固定字节。同样的,物理内存被分割为物理页(Physical Page PP),大小也为固定字节(物理也成称为页帧,Page frame)。

在任意时刻,虚拟页面都分为三个不相交的部分:

  • 未分配的(Unallocated), VM 系统还未分配(或者创建)的页,未分配的页没有任何数据和它们关联,因此不占用任何内存/磁盘空间。
  • 缓存的(Cache):当前已缓存在物理内存中的已分配页
  • 未缓存的(UnCache):该页已经映射到磁盘上,但是还未缓存在屋里内存中。


    virtual.png

    这张图展示了在一个有 8 个页面的虚拟内存中,虚拟 0 和 3 还没有被分配,所以

其中未分配的VP不占用任何的实际物理空间。32位程序地址空间就有4G,至于64G的程序的地址空间也是非常的(2的64次),而目前我们电脑的高配也就2T,16G内存。如果64位程序每个VP都映射着实际的PP。无论如何也对不上。并且也完全没必要。

页表(page table)

系统必须得有办法判断某个虚拟页是否缓存在内存的某个地方。这具体分为两种情况:

  • 已经在内存中,就需要判断该虚拟页存在于哪个物理页中
  • 不在内存中,那么系统必须判定虚拟页存放在磁盘的哪个位置,并且在物理内存中选择一个牺牲页,并将该虚拟页从磁盘复制到内存,替换这个牺牲页。

这些功能由软硬件联合起来,包括操作系统,CPU 中的内存管理单元(Memory Management Unit,MMU)和一个存放在物理内存中叫页表(page table)的数据结构,页表将虚拟页映射到物理页。


pageTable.png

上图展示了一个页面的基本结构,页表是一个页表条目(Page Table Entry, PTE)的数组。虚拟地址的每个页都在页表中有一个对应的 PTE。在这里我们假设每个 PTE 是由一个有效位(Valid bit)和一个 n 位地址字段组成的。有效位表明了该虚拟页是否被缓存在内存中:

  • 有效位为1,则内存缓存了该虚拟页,地址字段表示内存中相应的物理页的起始位置。
  • 有效位为0,则地址字段的null表示这个虚拟页还未被分配,否则该地址就指向该虚拟页在磁盘上的起始位置。

页命中与缺页

在存储器层次结构中说过缓存命中与不命中的问题,都是缓存思想。磁盘与内存之间的缓存不命中代价肯定大的多。因为 L0 - L4 之间,每级缓存的速度大约相差了 10 倍左右,但是 L4 主存与 L5 磁盘之间,它们的速度相差十万倍。所以主存与磁盘之间交换的页容量是最大的,尽可能的增加命中率。

在存储器层次,每次替换的区域,是以块(block)为单位,在这里却是 页(page)。其实两者都是同一个意思,因历史原因叫法不同。

当 CPU 想要读取包含在某个虚拟页的内容时,如果该页已经缓存在主存中,也就是页命中。但是如果该页美欧缓存在内存中,则称之为缺页(page fault).


pageFault.png

Page fault: 指向虚拟内存,它不在物理内存中。
如上图所示, CPU 引用了 VP3 中的内容,VP3 并未缓存在主存中。系统从内存中读取 PTE3 时, 得知 VP3 未被缓存,这会触发一个缺页异常。缺页异常会调用 kernel 的缺页异常处理程序,该程序会选择一个牺牲页。如下图所示,牺牲页选择了存放在 PP3 中的 VP4.


vp4.png

此时如果 VP4 的内容被修改了,Kernel 会将它复制回磁盘的。接下来,Kernel 从磁盘赋值 VP3 到内存中的 PP3 并更新 PTE3。随后返回用户进程。当异常处理程序返回时,它会重启执行导致缺页的指令,当重新执行这条指令时,因为此时VP3已经在主存中,此时就是页命中。


vp3.png

这张图显示了 vp3 被缓存到 pp3.

根据习惯性的叫法,我们在磁盘和内存之间传递页的活动叫做交换(swapping)或者页面调度(paging)。这种交换活动,只有当不命中发生时才会发生(也就是当系统没有把磁盘内存预存到内存中)。这种策略叫做按需页面调度(demand)。

虚拟内存作为内存管理和内存保护的工具

理所当然,每个进程都有一个独立的页表和一个独立的虚拟地址空间.
比如每个 C 程序都要调用 stdio 这个库,不可能为每个进程都添加一份库,内存中只有一份 stdio 库的内容,供每个使用该库的进程共享。


reset.png

如上图所示,第一个进程的的页表将 VP2 映射到某个物理页面,而第二个进程的同样将它的 VP2 映射到该物理页面。所以该物理页面被这两个进程所共享。

在 c 语言中存在指针,可以直接进行内存操作。因为有了虚拟内存,所以我们的指针操作也不会访问到其他进程的区域,但是哪怕对于自己的地址空间,很多内存区域也应该是禁止访问的,这不仅包括 kernel 的区域,也包括自己的只读代码段。那么虚拟内存就提供了这样的一种内存保护工具。

地址翻译机制可以使用一种自然的方式来提供内存的访问控制。PTE上添加一些额外的控制位来添加权限。每次 CPU 生成一个地址时,地址翻译硬件都会读一个 PTE。


virtualProtected.png

虚拟内存提供内存保护,在上图中,每个 PTE 额外添加了三个控制位,SUP 表示进程是否必须运行内核模式,READ 和 WRITE 分别控制页面的读写权限。如果有指令违反了这些控制权限,那么 CPU 会触发一个故障,并将控制传递给内核中的异常处理程序。这种异常被称为段错误(segmentation fault)

段和页

页是操作系统为了管理主存方便而划分的,对用户不可见。但是思考这个情况,一个页的大小是 1 M,但是某个程序数据加起来也就 0.5 M,所以在内存和磁盘进行页交换明显浪费了内存。所以还有一种划分方式是分段。

swap 分区的作用

linux 有一个 swap 分区,它的作用是当系统的物理内存不够用的时候,就要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自于一些很长时间也没有什么操作的程序,这些被释放的空间中的信息被临时保存到 Swap 区域,等到那些程序要运行时,再从 Swap 中唤醒,恢复保存的数据到内存中。系统总是在物理内存不够时,才进行 Swap交换。

特别注意,按照字面意思,swap 交换区也可以称为虚拟内存。硬盘上的 swap 交换区,其实就相当于承担了内存的作用。swap 交换区起到了扩大内存的作用。所以从某种意义上讲,swap 区也可以叫做虚拟内存,但是这个虚拟内存是字面意思,和我们本文中站在计算机系统角度来解释的虚拟内存不是一个概念。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容

  • 概述 我们都知道一个进程是与其他进程共享CPU和内存资源的。正因如此,操作系统需要有一套完善的内存管理机制才能防止...
    SylvanasSun阅读 3,855评论 0 25
  • 操作系统对内存的管理 没有内存抽象的年代 在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物...
    Mr槑阅读 16,709评论 3 24
  • 虚拟存储器又叫做虚拟内存,我们现在的操作系统普遍都支持了虚拟内存,这样做是因为我们同时运行着太多的程序了,就目前我...
    唐鱼的学习探索阅读 4,911评论 1 25
  • word直接复制来了,格式就不改了。至于这门课怎么复习,只要平时实验都认真完成、报告认真写,平时分都很高;考试的话...
    Jozhn阅读 4,566评论 0 8
  • 时间随呼吸在不经意间悄悄溜走,渐渐炎热的即将结束的五月,总是在刺眼的阳光下容易迷失自己,慵懒的思想给自己一次又一次...
    夏目Kiki阅读 145评论 0 1