Java教程

程序员的基础知识----虚拟内存

本文主要是介绍程序员的基础知识----虚拟内存,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

3.虚拟内存

文章目录

      • 3.虚拟内存
          • 3.1分页
          • 3.2页表
          • 3.3 加速分页过程
            • 转换检测缓冲区(TLB)
          • 3.4针对大内存的页表
            • 多级页表
            • 倒排表

​ 当代计算机程序以经大到内存无法容纳,而且还需要支持多个程序运行。

​ 20世纪60年代所采用的方法是:把程序分割成许多片段,称为覆盖。

​ 在程序运行的时候,需要那个片段或者模块,由操作系统动态的换入换出至内存。那么分割就需要程序员去操作了,所以呀,操作难度极大,很少有程序员擅长这项技术。这个时候虚拟内存应运而生。

虚拟内存,使得每个程序都拥有自己的内存地址,这个空间被分割成多个快,每一块称之为一页或者页面.每一页有连续的地址范围,这些页被映射到物理内存。 并不是整个程序都在内存中,程序才能够运行。程序引用到一部分在物理内存中的地址空间时,由硬件立即执行映射。当程序应用的页面不在物理内存中时,由操作系统负责把缺失的部分装入物理内存并重新执行失败的指令。简而言之,就是你用那一块页面,就调那一块。因为程序是一步步执行的,只要能满足现阶段就ok.

​ 为什么说,虚拟内存适合多道程序设计呢,在我们读取其他页面的时候,cpu就闲下来了,这时候就可以让cpu去执行另外的一个进程,提高了cpu的利用率。

3.1分页

​ 虚拟内存,让每个程序都有了自己的(虚拟)地址空间,那么虚拟的空间肯定会大于真是的物理空间,那么他就肯定需要一个机制去映射和管理,完成虚拟-----> 物理 的映射。

因为程序执行需要加载到内存上,那么虚拟内存又是在干什么呢?他类似于在磁盘上给你一个空间,给他们标记上地址编码,等我们需要的时候,能够以最快的速度找他程序的页面,并加载其进入内存。

​ 这样呢,就出现了一个机制叫 内存管理单元(Memory Management Unit ,MMU),他就负责怎么将虚拟内存转换成物理内存。

image-20210514194156747

​ CPU不会直接将虚拟内存发送给地址总线,而是将其先发送给MMU,经过MMU的映射之后,在传输到地址总线。

image-20210610203605535

​ 虚拟地址按固定大小划分称为页面的若干单元,物理内存对应的单元称为页框。

​ 从64k程序虚拟地址空间到32k的物理地址空间,虚拟内存空间,还有一位用来标志是否在内存中,或者说是是否建立映射关系。当访问的页面不在内存中时,则产生缺页中断,操作系统建立映射(或者替换一个页面建立映射)。

3.2页表

​ 虚拟地址到物理地址的映射:

​ 虚拟地址被分成虚拟页号(高位部分)和偏移量(低位部分)两个部分。

image-20210610210841422

​ 通过上述机制,我们就可以实现虚拟程序地址,到物理地址的转化。

​ 虚拟内存本质上是一个新的抽象概念—地址空间,是对物理空间的一个抽象,解放物理内存在使用过程中,一些问题。

​ 虚拟内存MMU的实现从某种程度上讲还是对基址寄存器与界限寄存器的一种综合实现。

3.3 加速分页过程

​ 上述我们看到的分页,但是每一次的抽象都会带来效率上的各种问题。

​ 分页我们就必须保证:

​ 1.虚拟地址到物理地址的映射必须快

​ 2.如果虚拟地址很大,页表也会很大

​ 物理内存是有限的,在映射过程中,我们不仅仅是要查询,产生缺页中断,我们还要替换,甚至当内存数据发生改变的时候,我们还需要将数据写回磁盘。就查询而言,即使是小的程序,执行机器语言查询指令地址和数据地址也数不胜数呀,那么这些问题,我们需要怎么解决呢?

转换检测缓冲区(TLB)

因为大多数的程序总是对少量的页面进行多次访问,那么,也只有很少的页表会被反复的读取。

​ 转换检测缓冲区,是一个直接将虚拟地址映射成物理地址的硬件设备。

​ 它设计在内存管理单元之中,一般大小不超过64个。它的作用和其他的缓冲区一样,当程序运行的时候,它会记录最近最常使用的页面信息,当一个虚拟地址放入MMU中时,会先从TLB匹配虚拟页号,如果存在就直接调用;如果不存在,再去访问页表,进行替换。

​ 现在的机器的页面管理大部分都是由软件管理的,这样做为cpu芯片的高速缓存以及其他腾出大量空间。

​ 为了减少TLB失效,计算机预先装载程序,也会在内存中维护一个固定位置的TLB页表的软件告诉缓存。

​ 这里说一下TLB时效:

​ 软失效:访问页面在内存中,不在TLB中。

​ 硬失效:访问页面不在内存中,需要磁盘取出。

3.4针对大内存的页表

​ 引入TLB,加速虚拟内存地址到物理地址的转化。但是,问题又来了特别大虚拟空间时,页表会特别大,全部加载到内存中势必会浪费很大一部分空间,这时应该怎么处理呢。

多级页表

image-20210611170658394

​ **引用多级页表可以避免把把全部的页表一直保存在内存中。**特别时那些不用的页表,就更不应该保留了。

​ 如上图,在左边时顶级页表,他有1024个表项,对应于1024PT1域。当一个虚拟地址被送到MMU时,MMU首先提取到PT1,在顶级页表中找到二级页表的索引,在去二级页表中,找到PT2,加上偏移位Offset,那么就可以找到对应的页面了。

​ 当然,大家看到二级页表,肯定就会有三级、四级等更多级,级别越多,灵活性也会增大,复杂度也会增大。

倒排表

​ 现在的计算机基本都是x64位的。如果现在的地址空间264字节,页面大小4KB,我们需要252个表项的页表。如果一个表项8个字节,呢么整个页表就会超过3000万GB。仅仅为页表消耗,这么多多的空间可不是个好主意。

​ 解决方案就是倒排页表。

​ 先介绍一下倒排表,当你打开《现代操作系统》这本书,看到的目录一样,你可以通过目录去找到对应的页面,他和目录不同的是,他没有序号,也就是无序的。也就是说当你想找内存管理是,你只能一个一个遍历目录 找到对应的页框(*)。

这里补充一下页和页框的区别:
    一页是指一系列的线性地址和包含的数据。
    页框是*内存*中的实际存储区域。
    一般情况下,页和页框是一样大小的。
    页只是一组数据块,可以存放在实际存储区域。
    我感觉还是没有讲清楚,磁盘中存在4kB一页数据,我们要将一页数据放在一个页框中。

​ 当进程n,访问页面p时,我们需要去倒排表中,遍历寻找对应的页框。每次遍历倒排表,无意时非常费时的工作。那么我们可能会想到TLB,来个这个不就好了吗,没有问题,但是TLB会失效,当失效时,我们还是需要去遍历整个倒排表。

​ 先辈们,给出了散列表。

image-20210611183559395

​ 通过虚拟地址来散列,当前所有在内存中的具有相同散列值的虚拟页面被链接在一起。如果散列表中的索引数和物理内存页面数目相同,那么散列表只有一个表项,大大提高了映射速度。一旦页框号被找到,我们就将其(虚拟页号,物理页框号)对就会加入TLB中,散列提高查询速度,TBL提供缓存,大大提高了效率。

这篇关于程序员的基础知识----虚拟内存的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!