虚拟内存机制

1.为什么要有虚拟内存
在早期的计算机中,是没有虚拟内存的概念的。我们要运行一个程序,会把程序全部装入内存,然后运行。
当运行多个程序时,经常会出现以下问题:
1)进程地址空间不隔离,没有权限保护。
由于程序都是直接访问物理内存,所以一个进程可以修改其他进程的内存数据,
甚至修改内核地址空间中的数据。
2)内存使用效率低
当内存空间不足时,要将其他程序暂时拷贝到硬盘,然后将新的程序装入内存运行。
由于大量的数据装入装出,内存使用效率会十分低下。
3)程序运行的地址不确定
因为内存地址是随机分配的,所以程序运行的地址也是不确定的。

2.虚拟地址和物理地址
对于32位系统,寻址指针为4字节,对应的虚拟地址空间为0-2^32,即0-4G。
对于64位系统,寻址指针为8字节,对应的虚拟地址空间为0-2^64,即0-16G。
要注意的是,这个地址空间是虚拟的,并非实际存在的。
Linux内核把虚拟地址空间分为两部分:用户进程空间,内核进程空间。
如下入所示:

在缓存原理中,换入/换出的数据以块为最小单位。在内存管理时,页是地址空间的最小单位。
虚拟地址空间划分为多个固定大小的虚拟页(VP),物理地址空间(DRAM内存)划分为多个固定大小的物理页(PP),
虚拟页和物理页的大小是一样的,通常为4KB。

虚拟页和物理页存在着以下关系:
虚拟页和磁盘文件映射,然后缓存到物理页。
根据是否映射,是否缓存,可以将虚拟页的状态分为以下三种:
1)未映射的页
即虚拟页没有映射到磁盘文件
2)未缓存的页
虚拟页映射到了磁盘文件,但是没有缓存到物理页,也就是内存上。
3)缓存的页
虚拟页映射到了磁盘文件,并且缓存到物理页
如下图所示:

3.虚拟地址的工作原理
对于进程来说,使用的都是虚拟地址。每个进程维护一个单独的页表。何为页表?
页表是一种数组结构,存放着各虚拟页的状态,是否映射,是否缓存。

1)数组的索引号,表示虚拟页号
2)数组的值
若为null,表示未映射的页
若非null,第一位表示有效位,为1,表明缓存的页;为0,表明未缓存的页。
其余位表示缓存到的物理页号。

页表结构图如下:

进程执行时,当需要访问虚拟地址中存放的值时,步骤如下:
1)CPU会先找到虚拟地址所在的虚拟页(VP3),根据页表,找出页表中第3条的值。
判断有效位,为1,DRMA缓存命中,获根据物理页号,找到物理页中的内容,返回。
2)若有效位为0,产生缺页异常,调用内核缺页异常处理程序。
它会选择一个物理页(如PP4),作为牺牲页,将该页的内容刷新到磁盘文件。然后,把VP3映射的磁盘文件,缓存到该物理页。
页表中的第3条,有效位变1,同时,物理页号表号变为PP4。
3)缺页异常处理完毕后,返回中断前的指令,重新执行,此时缓存命中,执行1)
4)将找到的内容映射到高速缓存,CPU从高速缓存中获取该值,结束。

4.使用虚拟地址需要注意的问题
1)磁盘和主存传送页的活动叫做页面调度。页面调度会引起磁盘流量,如果程序的局部性不好,会频繁进行页面调度,叫做“缓存颠簸”。
操作系统会在内存中分配一块交换区作为缓冲区,来加速页面的调度。
2)一级页表占用的空间是比较大的,根据按需调度的原则,一般使用的是多级页表,即一级页表指向二级页表,这样大大压缩了页表的大小。

5.地址翻译
地址翻译指的是DRAM缓存命中时,由虚拟地址找到物理地址的过程。
该过程是完全由硬件来完成的。
1)CPU有一个专门的页表基地址寄存器(PTBR)指向当前页表的基地址,快速定位到该进程的页表。
2)根据虚拟页号,找到虚拟地址在页表的值。
3)根据值中的物理页号,找到物理地址。

6.Linux中的虚拟内存机制

Linux把虚拟内存划分成区域area的集合,一个area包括连续的多个页。
area的数据结构如下所示:
1)内核为每个进程维护了一个单独的任务结果task_struct
2)task_struct的mm指针,指向了mm_struct,该结构描述虚拟内存的运行状态。
3)mm_struct的pgd指针指向进程的一级页表的基地址。
mmap指针,指向vm_area_struct链表。
4)vm_area_struct描述area的结构,vm_start表示area的开始位置,vm_end表示area的结束位置,vm_prot表示area内的页的读写权限,vm_flags表示area内的页面是进程私有还是共享,vm_next指向下一个area节点。

在Linux中,当发生缺页异常时,步骤如下:
1)缺页异常程序,检查虚拟地址在哪个area内。
2)访问的虚拟页若没有读写权限,则触发一个保护异常,终止进程。
3)选择牺牲页,刷新到磁盘,从磁盘加载缺失的内容到物理页,更新页表。

7.Linux虚拟内存需要注意的问题
内存映射机制:初始化虚拟内存区域时,会把虚拟内存和磁盘文件对象对应起来。

由于内存映射机制,一个磁盘文件对象可被多个进程共享访问,也可被多个进程私有访问。
当共享访问时,一个进程的对该对象的修改会显示到其他进程。
当私有访问时,修改时会产生保护故障,内核会拷贝这个私有对象,修改的是这个新对象,其他进程指向的是原来的对象。

fork函数是说明内存映射机制很好的例子:
fork函数会创建带有独立虚拟地址空间的新进程,内核会把当前进程的虚拟内存中数据结构复制一份给新进程。虚拟内存area包括共享区域和私有区域,新建的进程对私有区域做修改时,会触发写时拷贝,为新进程维护私有的虚拟地址空间。

8.虚拟地址作用总结
1)虚拟内存管理可以控制物理内存的访问权限
访问的虚拟页若没有读写权限,则触发一个保护异常,终止进程。
2)虚拟内存让每个进程有独立的地址空间
对于私有区域来说,当不同进程对该区域做修改时,会触发写时拷贝,为新进程维护私有的虚拟地址空间。
3)VA到PA的映射会给分配和释放内存带来方便。
物理内存不连续的地址,可映射到连续的虚拟内存地址。
4)内存效率高
使用了页面调度,不会造成大量的数据装入装出。

参考资料: 《深入理解计算机系统》

时间: 2024-10-14 02:43:18

虚拟内存机制的相关文章

计算机底层知识拾遗(一)理解虚拟内存机制

这个系列会总结计算机,网络相关的一些重要的底层原理.很多底层原理大家上学的时候都学过,但是在学校的时候大部分的同学都是为了应付考试而学习,过几天全忘了.随着工作的时间越久,越体会到这些基础知识的重要性.做技术和练武功一样,当你到了一定的阶段,也会遇到一个瓶颈,突破了你的眼界就会大不同,突破不了,只能困在原地无法成长.我自己深有体会,这些基础知识,底层原理是助你打破瓶颈的灵丹妙药.当理解了一些底层原理之后,会发现现在很多热门技术,原理,常见的设计都是在底层基础上发展而来的. 这篇总结一下单机系统的

windows虚拟内存机制

在windows系统中个,每个进程拥有自己独立的虚拟地址空间(Virtual Address Space).这一地址空间的大小与计算机硬件.操作系统以及应用程序都有关系. 对于32位程序来说,最多能使用2GB空间(0x00010000-0x7FFEFFFF).为了获得3GB的地址空间,在不同的windows系统中可以按照如下方法来进行扩充. 1.操作系统方面 ① 32位windowsXP ② 32位win7 -- 管理员权限执行命令:bcdedit /set increaseuserva 307

Linux的分段和分页机制

1 基于80x86的Linux分段机制 80386的两种工作模式:80386的工作模式包括实地址模式和虚地址模式(保护模式).Linux主要工作在保护模式下. 在保护模式下,80386虚地址空间可达16K个段,每段大小可变,最大达4GB.逻辑地址到线性地址的转换由80386分段机制管理.段寄存器CS.DS.ES.SS.FS或GS各标识一个段.这些段寄存器作为段选择器,用来选择该段的描述符. 分段逻辑地址到线性地址转换图: Linux对80386的分段机制使用得很有限,因为Linux的设计目标是支

计算机底层知识拾遗(三)理解磁盘的机制

磁盘是一种重要的存储器,位于主存结构的下方,是永久存储的介质.在计算机底层知识拾遗(一)理解虚拟内存机制 这篇中说了虚拟内存是面向磁盘的,理解磁盘的工作原理对理解计算机的很多概念有很大的帮助.尤其是在数据库和分布式存储领域,要经常和磁盘打交道. 磁盘这块主要有几个部分的概念: 1. 磁盘的基本结构和工作原理 2. 如何在虚拟内存机制下与内存高效地交换数据 3. 磁盘如何保证数据存储的可靠性及故障恢复 磁盘的基本结构和工作原理 从单个磁盘来说,由一个个的同心圆组成,一个同心圆就是一个磁道,每个磁道

辛星浅谈Redis中的虚拟内存

和大多数NoSQL一样,Redis也是使用的KV的数据存储模型,为了提高读写效率,Redis也是将KV保存在内存中,但是这样做会带来一些问题. 如果 内存足够大,那么把所有的数据都加载到内存中固然是最好的选择,那么查询操作都直接操作内存,自然是很快.但是实际情况中却更多的是只有部分数据才能加载到内存中,那么这个时候就提出来一个虚拟内存的概念. Redis中的虚拟内存和Linux中的虚拟内存不是一回事,但是其思想是一致的,就是把暂时不常用的数据从内存交换到磁盘中,从而可以把宝贵的内存腾出来用于其他

自学总结redis第三部分(安全性、主从、哨兵、事物、持久化、发布与订阅、虚拟内存)

八.redis的安全性 因为redis速度相当快,所以在一台比较好的服务器下,一个外部用户在一秒内可以进行15W次的密码尝试,这意味着需要设定非常强大的密码来防止暴力破解. 可以通过设置密码以及登录redis方式来操作,具体参考 九.redis主从复制 9.1简介 1.Master可以拥有多个slave. 2.多个slave可以连接同一个master外,还可以连接到其他的slave. 3.主从复制不会阻塞master,在同步数据时,master可以继续处理client请求. 4.提供系统的伸缩性

Linux 虚拟内存

什么是虚拟内存? 先直接摘抄一段 wikipedia 上的介绍. 虚拟内存是计算机系统内存管理的一种技术.它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换. 对于 C 语言里面的变量,我们可以使用 & 运算符来获得其地址, 既然是虚拟地址,就是指这个地址是虚拟的. 虚拟地址机制不是必须的,在简单的单片机中,编写的代码编译时都需要指定物理 RAM 空间分布,不会有虚拟地址的概念,

Redis资料汇总(九) 虚拟内存

首先说明下redis的虚拟内存与os的虚拟内存不是一码事,但是思路和目的都是相同的.就是暂时把不经常访问的 数据从内存交换到磁盘中,从而腾出 宝贵的 内存空间用于其他需要访问的数据.尤其是对于redis这样的内存数据库,内存总是不够用的.除了可以将数据分割到多个redis server外.另外的能够提高数据库容量的办法就是使用vm把那些不经常访问的数据交换的磁盘上.如果我们的存储的数据总是有少部分数据被经常访问,大 部分数据很少被访问,对于网站来说确实总是只有少量用户经常活跃.当少量数据被经常访

理解 Linux 的虚拟内存

前言 前不久组内又有一次我比较期待的分享:”Linux 的虚拟内存”.是某天晚上加班时,我们讨论虚拟内存的概念时,leader 发现几位同事对虚拟内存认识不清后,特意给这位同学挑选的主题(笑). 我之前了解一些操作系统的概念,主要是毕业后对自己大学四年的荒废比较懊恼,觉得自己有些对不起计算机专业出身,于是在工作之余抽出时间看了哈工大在网易云课堂的操作系统公开课,自己也读了一本讲操作系统比较浅的书 <Linux内核设计与实现>,而且去年自己用 C 写简单的服务器时,也追根究底了解了更多的系统底层