存储管理
第一节是从物理内存的角度来说;第二节是从进程角度理解进程的存储空间管理。
一.内存分配与回收
早期计算机编程并不需要过多的存储管理,随着计算机和程序越来越复杂,存储管理成为必要。
存储管理主要解决三个问题:
- 确保计算机有足够的内存处理数据
- 确保程序可以从可用内存中获取一部分内存使用
- 确保程序可以归还使用后的内存以供其他程序使用
1.1 内存分配的过程
有以下三种分配方法
1.1.1 单一连续分配(过时)
单一连续分配是最简单的内存分配方式,只能在单用户、单进程的操作系统中使用。
该方法将内存分为系统区和用户区,系统区内存只能给操作系统使用,用户区的内存只能给用户使用。
1.1.2 固定分区分配
固定分区分配是支持多道程序的最简单存储分配方式,内存空间被划分为若干固定大小的区域(分区),每个分区只提供给一个程序使用,互不干扰。
1.1.3 动态分区分配
根据进程实际需要,动态分配内存空间。
下面介绍该方法相关的数据结构、分配算法:
1.1.3.1 相关数据结构
- 动态分区空闲表
每个空闲区对应一个0/1标记。0表示空闲区没有被使用,1表示空闲区被使用。 - 动态分区空闲链表
是一个双向链表,每个节点是一个空闲区,同时记录空闲区容量。相邻空闲区可以合并为一个节点。
1.1.3.2 相关算法
- 首次适应算法(FF算法)
分配内存时从开始顺序查找适合(大小满足)内存区,若没有合适的空闲区,则该次分配失败。
缺点:每次从头部开始,使得头部地址空间不断被划分,并且会有很多碎片。 - 最佳适应算法(BF算法)
最佳适应算法要求空闲区链表按照容量大小排序,遍历空闲区链表找到最佳合适空闲区。
优点:避免大材小用 - 快速适应算法(QF算法)
快速适应算法要求有多个空闲区链表,每个空闲区链表存储同一种容量的空闲区。
1.2 内存回收过程
内存回收区在内存中有四种情况(假设使用空闲链表保存空闲区):
- 回收区与空闲区相连,且在空闲区后面
回收过程:只需要把空闲区的容量增大为包含回收区即可。 - 回收区与空闲区相连,且在空闲区前面
回收过程:将回收区与空闲区合并为新的空闲区,新的空闲区使用回收区的地址。 - 回收区与空闲区相连,且在两块空闲区之间
回收过程:将前后两个空闲区和回收区合并,新的空闲区合并之前的回收区之前的空闲区地址。 - 单一回收区且不与任何空闲区相连
回收过程:为回收区创建新的空闲节点,插入到相应的空闲区链表中去。
二.段页式存储管理
2.1 页式存储管理
字块是相对物理设备的定义,页面则是相对逻辑空间(进程空间)的定义。
页式存储管理就是将进程逻辑空间等分成若干大小的页面,相应的把物理内存空间分成与页面大小相同的物理块,以页面为单位把进程空间装进物理内存中分散的物理块(字块)。
页面大小 应该适中,过大难以分配,过小内存碎片过多,页面大小通常是512B~8K。
如何知道进程的页面分配到哪一个物理块(字块)呢?
页表:记录进程逻辑空间与物理空间的映射。有两项:页表、字块。
页地址对应字的地址,页地址也是分为两部分,前m位(页号)是页面在页表的索引,得到该页的物理块(字块);后b位(页内偏移)指定页面在物理块(字块)中的地址。
页表在现代计算机系统中的问题:
现代计算机系统中,可以支持非常大的逻辑地址空间(232~264) ,这样,页表就变得非常大,要占用非常大的内存空间。比如,具有32位逻辑地址空间的分页系统,规定页面大小为4KB,则在每个进程页表中的页表项可达1M(220)个,如果每个页表项占用1Byte,故每个进程仅仅页表就要占用1MB的内存空间。
为解决这一问题,引出多级页表。只需要在运行时候加载根页表,之后按需查找二级页表……
页式存储管理的缺点:有一段连续的逻辑分布在多个页面中,将大大降低执行效率。
2.2 段式存储管理
将进程逻辑空间划分(非等分)成若干段,段的长度由连续逻辑的长度决定。比如,逻辑里面有主函数MAIN、子程序段X、子函数Y等,按照每一个函数的逻辑长度分配逻辑空间(段)。
段表:记录进程逻辑空间与物理空间的映射。有三项:段号、基址、段长。
段地址:段号、段内偏移两部分组成。类比页地址。
2.3 页/段式存储管理同异
- 相同点:段式存储和页式存储都离散地管理了进程的逻辑空间
- 不同点:页是物理单位,段是逻辑单位;分页是为了合理利用空间,分段是满足用户要求;页大小由硬件固定,段长度可动态变化;页表信息是一维的,段表信息是二维的
2.4 段页式存储管理
分页可以有效提高内存利用率(虽然说存在页内碎片),分段可以更好满足用户需求。二者取其优,结合为段页式存储管理。
段页式存储管理先将逻辑空间按段式管理分成若干段,再把段内空间按页式管理等分成若干页。
段页地址:由三部分组成。段号是进程逻辑空间具体哪一段;段内页号是段里具体某一页;页内地址是某一页里具体的字。
三.虚拟内存
一个游戏十几G,物理内存只有4G,那这个游戏是怎么运行起来的?
3.1 虚拟内存概述
为什么需要虚拟内存?
- 有些进程实际需要的内存很大,超过物理内存的容量
- 多道程序设计会使多个进程在内存当中,使得每个进程可用物理内存更加稀缺
- 不可能无限增加物理内存,物理内存总有不够的时候
虚拟内存是操作系统内存管理的关键技术,使得多道程序运行和大程序运行成为现实。
工作方式:把程序使用内存划分,将部分暂时不使用的内存放置在辅存中,使用辅存保存之后可能用到的部分。
3.2 程序的局部性原理
局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访的存储单元都趋于聚集在一个较小的连续区域中。
程序运行时,无需全部装入内存,装载部分即可;如果访问页不在内存,则发出缺页中断,发起页面置换;从用户层面看,程序拥有很大的空间,即是虚拟内存。
虚拟内存实际是对物理内存的补充,速度接近于内存,成本接近于辅存。
3.3 虚拟内存的置换(页面替换)算法
- 先进先出算法(FIFO)
- 最不经常使用算法(LFU)
- 最近最少使用算法(LRU)
与高速缓存替换算法细节一样
3.3.1 高速缓存/主存页面替换的比较
高速缓存替换 | 页面替换 | |
---|---|---|
时机不同 | CPU读取缓存时没有找到对应数据, 缓存需要从主存中载入相关数据 | 主存缺页时,主存需要从辅存载入页面数据 |
层次不同 | Cache-主存层次 | 主存-辅存层次 |
目的不同 | 解决速度问题 | 解决容量问题 |
这也是为什么计算机存储器分层的一个原因。