计算机这个行业的历史上有过很多成功的预言,最著名的自然是“摩尔定律”。当然免不了的也有很多“失败”的预测,其中一个最著名的就是,比尔·盖茨在上世纪 80 年代说的“640K ought to be enough for anyone”,也就是“640K 内存对每个人来说都够用了”。
而在现在,我们身边的机器的内存已经是4G,甚至动辄就是16G/32G的内存,如果你当时听到比尔盖茨的这句话的时候,你是不是觉得这个根本就是无稽之谈呢?那么我们就来看看这个技术是怎么做的呢?
1. 覆盖技术
覆盖技术主要用于早期的OS中(内存<64K),可用于存储空间受限,某些大作业不能一次全部装入内存,产生了大作业和小内存的矛盾。而覆盖技术就是解决这一矛盾,在较小的可用内存中运行较大的程序。其基本的思路如下:
- 1.对于进程,不需要一开始就把程序的全部指令和数据装入内存中执行,常用功能的代码和数据常驻内存,不常用功能放在其他程序模块中,只在需要用到时装入内存
- 2.程序划分为若干个功能上相对独立的程序段,按照程序逻辑结构让那些不需要同时执行的程序共享同一块内存区
- 3.当有关程序段的先头程序已经执行结束后,再把后续程序段从外存调入内存覆盖前面的程序段
程序员必须把一个程序划分成不同的程序段,并规定好它们的执行和覆盖顺序,例如如下实例中,设某进程的程序正文段由A,B,C,D,E和F等6个程序段组成
由于程序段B不调用C,程序段C也不调用B,因此程序段B和C无需同时驻留在内存,它们可以共享同一内存区。
同理,程序段D、E、F也可共享同一内存区。所以对于程序实际需要的内存空间是190K,而采用覆盖技术后,实际的地址空间只需要最少100K就可以了。
虽然覆盖技术可以解决小内存,大应用的问题,但是也存在它自身的局限性
- 增加编程困难:需程序员划分功能模块,并确定模块间的覆盖关系,增加了编程的复杂度
- 增加执行时间:从外存装入覆盖模块,时间换空间
- 只能发生在没有调用关系的模块间,程序员须给出模块间的逻辑覆盖结构
- 发生在运行程序的内部模块间
这个技术对于编程人员的能力要求很高,同时如果程序过于复杂,出错可能性很大,最重要的一点是,这个发生在运行程序的内部,那如果是程序间的空间大于内存空间,那么就会导致无法解决小内存,大应用的问题。
2. 交换技术
怎么更好地利用内存,UNIX让OS管理而不是程序员管理,以运行的程序为单位。多道程序在内存中时,让正在运行的程序或需要运行的程序有更多的内存资源。其基本思路如下:
- 可将暂时不能运行的程序送入外存中,从而获得空闲内存空间
- 换出(swap out):把一个进程的整个地址空间保存到外存
- 换入(swap in):将外存中某进程的地址空间读入到内存
- 换入换出的基本单位:整个进程的地址空间
对于交换技术,我们需要思考几下几个问题
- 交换时机的确定:何时需要发生交换?-----只有当内存空间不够或者空间有不够使用的时候
- 交换区的大小:必须足够大以存放所有用户进程的所有内存映像的拷贝,必须能对这些内存映像进行直接存储
- 程序换入时重定位:必须采用动态地址映射的方法,保证程序换出后,再次换入的内存位置不需要在原来的位置。
总之,交换技术是以在内存中程序大小为单位进行,它不需要程序员给出各个模块间逻辑覆盖结构,是由操作系统来完成。
3. 局部性原理
一个优秀的程序、优美的代码,往往具有良好的局部性。那么什么是程序的局部性原理呢?
程序局部性原理:是指程序在执行时呈现出局部性规律,即在一段时间内,整个程序的执行仅限于程序中的一部分。相应地,执行所访问的存储空间也局限于某个内存区域,具体的来说,局限性通常有两种形式:
- 时间局限性:被引用过一次的存储器位置在未来会被多次引用(通常在循环中),一条指令的一次执行和下次执行,一个数据的一次访问和下次访问都集中在一个较短时期内
- 空间局限性:如果一个存储器的位置被引用,那么将来他附近的位置也会被引用,当前指令和邻近的几条指令,当前访问的数据和邻近的几个数据都集中在一个较小区域内
从理论上来说,虚拟存储技术是能够实现的,而且可取得满意的效果。下面我们以一个例子不同程序编写方法的局部性特征,页面大小为4K,分配给每个进程的物理页面数为1。在一个进程中,定义了如下的二维数组int A[1024][1024],采用下面两种方式
for(j=0;j<1024;j++)for(i=0;i<1024;i++)A[i][j]=0; | for(i=0;i<1024;i++)for(j=0;j<1024;j++)A[i][j]=0; |
---|---|
发生了1024×1024次缺页中断 | 发生了1024次缺页中断 |
对于如果内存空间不足,就可以采用这种分页加载的方式。
4. 虚拟存储技术
随着技术的发展,覆盖和交换技术已经不能满足现实生活中的应用,虚拟存储技术就是优化覆盖技术,系统自动完成,综合交换技术,进程的部分内容交换,并且利用程序局部性原理。
4.1 虚拟存储技术的概念
虚拟内存是指在具有层次结构存储器的计算机系统中,采用自动实现部分装入和部分交换功能,为用户提供一个比物理主存容量大的多的可寻址的一种“主存储器”。它使用逻辑存储器与物理存储器分离,是操作系统给用户提供的一个比真实内存空间大的多的地址空间。虚拟存储的基本思路:将不常用的部分内存块暂存到外存,其基本原理如下:
- 基于局部性原理,装载程序时,只将当前指令执行需要的部分页面或段装入内存
- 指令执行中需要的指令或数据不在内存(称为缺页或缺段)时,处理器通知操作系统将相应的页面或段调入内存
- 如果内存空间不足,操作系统将内存中暂时不用的页面或段保存到外存
那么基于虚拟内存的原理,可以有以下三个主要特征:
- 多次性 :无需再作业运行时一次性全部装入内存,而是允许被多次调入内存。
- 对换性 :在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入、换出
- 虚拟性 :从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际容量。
那讲了那么多虚拟内存技术的概念,我们肯定会想怎么实现这个虚拟内存技术啊?虚拟内存技术,允许一个作业分多次调入内存。如果采用连续分配方式,会很不方便实现(进程的地址连续)。因此,虚拟内存的实现需要建立在 离散分配 的内存管理方式基础上,结合之前的分段,分页,段页式管理,有以下几种方式
- 虚拟页式存储 ,基于传统分页存储管理
- 虚拟段式存储 ,基于传统分段存储管理
- 虚拟段页式存储 ,基于传统的段页式存储管理
4.2 虚拟页式存储管理
在页式存储管理的基础上,增加请求调页和页面置算法,就形成了现在的虚拟页式存储管理。其基本的思路如下:
- 1.基于局部性原理,在程序装入时,可以将程序中很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行
- 2.在程序在执行过程中,当所需要的访问代码或数据不在内存时,则向系统发出缺页异常请求,操作系统在处理缺页异常时,将外存中相应的页面调入内存,使得进程能继续运行
- 3.当内存空间已满,而又需要装入新的页面时,则根据某种算法置换出某个页面,装入新的页面
在使用虚拟页式存储管理时需要在页表中增加以下表项:
- 页号—页面的编号。
- 有效位—又称驻留位、存在位或中断位,表示该页是在内存还是在外存。如果为1,表示在内存中,页表项有效,可以访问,如果式,表示在外存,就需要产生缺页来将外存的数据替换到内存中
- 页框号—页面在内存中时所对应的内存块号。
- 访问位—又称引用位或参考位,表示该页在内存期间是否被访问过,页面置换算法时候会用到。
- 修改位—表示该页在内存中是否被修改过。回收时候,需要用此位来判断,是否要将内存的数据写回到外存
- 保护位—表示该页的访问方式,是否能读写执行。
- 禁止缓存位—采用内存映射I/O的机器中需要的位。
其基本的表示如下图
其转换关系如下图:
对于转换关系,与页式存储管理的转换关系基本类似,只是加了一个步骤,通过页表完成逻辑页号到物理帧号的转换后,需要通过有效位来检测,该访问数据是否是有效的,如果该位有效,说明数据在内存中,直接访问就可以了;如果有效位为0,说明该数据在外存中,就会产生一个缺页异常。
4.3 缺页异常处理流程
对于缺页异常的处理流程,还是结合上一章的例子来梳理下整个缺页异常的过程,当我们访问一个地址的时候,首先通过逻辑地址在页表中找,如果找不到或者找到了,但是其有效位是0,那么就会产生一个缺页异常,其处理框图如下,我们来梳理下缺页异常需要做那些操作
当产生缺页异常后,硬件就会通过MMU的机制在外存中寻找对应的页面,那么就会存在两种情况,一种是页面中存在空闲页,一种情况是不存在空间页
- 存在空闲页:在内存中有空闲物理页面时,分配一物理页帧f,将需要访问的页p装入到物理页面f,修改p的页表项驻留位为1,物理页帧号为f
- 不存在空闲页:依据页面置换算法选择将被替换的物理页帧f,对应逻辑页q,如q被修改过,则把它写回外存,将需要访问的页p装入到物理页面f,修改p的页表项驻留位为1,物理页帧号为f
其处理流程如下图
- 只有’写指令’才需要修改“修改位”,并且,一般来说只需要修改快表中的数据,只有将快表项删除时,才需要写回内存中,这样可以减小访问存储的次数
- 和普通的中断处理一样,缺页中断依然需要保留CPU现场
- 需要用某种置换算法来决定一个换出页面
- 换入/换出页面都需要启动慢速的I/O操作,可见,如果换入换出太频繁,会由很大的开销
- 页面调入内存后,需要块表项
5. 总结
对于虚拟存储技术,实现进程在内存与外存之间的交换,从而获得更多的空闲内存空间,虚拟存储空间就包括了物理的内存和硬盘。在虚拟存储中,页面在内存和外存之间频繁的调度以至于系统中页面所需的时间比进程实际运行的时间还多,在这种情况下,系统效率急剧下降,甚至可能出现全面崩溃。但是通过程序的局部性,虚拟存储技术是能够实现的,而且可取得满意的效果。
6. 参考资料
https://zhuanlan.zhihu.com/p/53004596
操作系统–清华大学
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。