操作系统 -- 虚拟内存
一.前言
在之前研究进程上下文切换和 golang 内存分配器的过程中,发现虚拟内存在其中都扮演着十分重要的角色,之前有学习和了解过虚拟内存,但是随着时间推移也只知道一个概念,现在想要带着问题去再学习一遍虚拟内存,希望这篇文章也能帮助你们更好的理解虚拟内存。
1.进程初始化的时候是如何分配的内存
2.虚拟内存的具体工作流程
二.详细介绍
2.1 简介
虚拟内存是一个抽象概念,它为每个进程提供了一个假象,即每个进程都在独占的使用主存。每个进程看到的内存都是一致的,称为「虚拟地址空间」。
虚拟内存主要提供了三个能力
它将主存看做是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式高效使用了主存
它为每个进程提供了一致的地址空间,简化了内存管理
它保护了每个进程的地址空间不被其他进程破坏
2.2 如何工作
如图所示,cpu 通过生产一个虚拟地址 4001 访问主存,虚拟地址再 mmu 的转换下映射为物理地址中的 2,通过讲翻译后的物理地址传给主存,主存读取从物理地址 2 开始的 4 个字节将其返回给 cpu。
2.3 名词解释
知道了大概的处理流程,接下来讲解一下虚拟内存相关的几个名词。
2.3.1 地址空间
一个非负整数地址的有序集合,在带有虚拟内存的系统中,cpu 从一个有 N=2^n 个地址的地址空间中生成虚拟地址,这个地址空间成为虚拟地址空间,要求是 2 的幂,一般由计算机的位数决定,如 32 位对应 2^32,64 对应 2^64。
物理地址空间则对应的是系统中物理内存的 M 个字节,没有 2 的幂的要求
2.3.1 页表
页表将虚拟页映射到物理页,每次地址翻译硬件将一个虚拟地址转换为物理地址时,都会读取页表,操作系统负责维护页表内容,以及在磁盘与 DRAM(Dynamic Random Access Memory)之间来回传送页。
页面分配的三种情况
页表是一个页表条目(pte:page table entry)的数组,每一条由一个有效位和一个 n 位地址字段组成,有效位表明了该虚拟页是否被缓存在 DRAM,如果有效,那么地址字段就表明了 DRAM 中的物理页起始地址。图中 vp1,vp2,vp4 都是这种情况。
若是空地址,则表明这个虚拟页还没有被分配,vp0 就是这种情况。
若是有地址,但是有效位为 0,那么就表明虚拟页被分配在了磁盘上,地址指向的就是虚拟页在磁盘的起始地址。
缺页
DRAM 缓存不被命中就叫做缺页。
如果我们去访问 vp3,就会发现 vp3 不在 DRAM 中,由于磁盘和 DRAM 的访问速度差了 100000 多倍,那么我们就需要将 vp3 缓存到 DRAM 中,此时我们将 vp3 从磁盘复制到物理内存(如果此时物理内存不够,就按照一定的算法将原本保存在里面的页面移出,并设置页表中对应的标记位为无效),再将 vp3 在页表中对应的 pte 有效位设置为有效,修改地址从磁盘指向 DRAM。
进程页表
虚拟内存为每个进程提供了一个独立页表,因而是一个独立的虚拟地址空间,一来方便用户操作,二来方便用户共享内存,因为不同的页表支持映射到同一个共享物理页面上。
2.4 地址翻译
2.4.1 名词介绍
页表基址寄存器(page table base register PTBR):在 cpu 寄存器中指向当前页表(进程上下文切换中要更换)
n 位虚拟地址:包含一个 p 位的虚拟页面偏移(virtual Page Offset,VPO)和一个 n-p 位的虚拟页号(virtual
page number,VPN),MMU 利用 VPN 来选择适合的 pte。物理页面的偏移量则与虚拟页面一致。
MMU(Memory Management Unit,内存管理单元):用于翻译虚拟地址和物理地址映射关系
2.4.2 地址翻译整体流程
cpu 生成虚拟地址,传递给 MMU
mmu 生成 pte 地址(这一步是 mmu 通过虚拟地址的虚拟页号获取的),并从高速缓存/主存得到它
高速缓存/主存将 pte 返回给 mmu
mmu 通过页表,构造物理地址,将其传给高速缓存/主存
高速缓存/主存将请求的数据字给处理器
2.4.3 TLB
由上面的知识,每次获取内存 mmu 都需要去内存取一次 pte,利用缓存思想(设计系统或者提高请求效率的时候都可以往这个上面靠,最基本原理就是空间换取时间),操作系统发明了 tlb(translation lookaside buffer),他是一个关于 pte 的小缓存(注意进程上下文切换也需要清空 tlb)。
有了 tlb,如果发生命中,那么过程如下。
cpu 生成虚拟地址,传递给 MMU
mmu 从 tlb 取出相应的 pte
mmu 将虚拟地址翻译成一个物理地址,并将它发送到高速缓存/贮存
高速缓存/主存将请求的数据字给处理器
三.问题思考
经过书本的系统学习,我已经了解了虚拟内存的工作原理,解决了问题二,还有进程初始化的时候是如何分配的内存这一问题。
以 linux 为例子,先看看在 linux 系统下进程的虚拟内存结构
进程能获取多少内存主要取决于运行时堆的内存分配,其余的内存消耗都是每个进程必要的,也就是说一个没有跑起来的进程消耗的内存都在物理内存上,等进程跑起来,会由操作系统对进程申请的内存进行动态分配,决定哪些放在物理内存,哪些放在主存,这是我们所不需要感知的。
四.参考文档
深入理解计算机系统
https://www.guru99.com/stack-vs-heap.html
版权声明: 本文为 InfoQ 作者【en】的原创文章。
原文链接:【http://xie.infoq.cn/article/3ab80769d5f6f317deb00b1b6】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论