2.内存管理
内存管理的作用?
操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情
设想有一个特别大篮子,在里面放东西,你会如何放置呢?或者如何做空间管理呢?如果每个程序都是分配实际的物理空间会引发什么问题呢,每个程序在分配内存前都需要查看实际空闲的内存空间,而且一旦分配后不可更改,很不灵活,分配的空间受物理内存大小限制,程序之前内存没有做隔离,而且我们都会知道实际物理地址,不安全。反过来说,虚拟内存的优点 ①安全性高。程序之前内存隔离 ②不受限于物理内存大小 ③程序内存统一管理。
动态重定位(基于硬件)
大概了解虚拟内存产生的背景,然后再开始思考如何设计?虚拟内存和物理内存之前肯定存在映射关系,第一种思路:动态重定位(基于硬件),每个cpu有2个寄存器-基址寄存器和界限寄存器,这样能保证我们可以在物理内存随意放置且可以保证进程只可访问自己的空间同时也不会超过实际的物理内存大小。映射关系:物理地址=虚拟地址+基址。由两个寄存器划定了每个进程的地盘,类似于两个指针数组,存储进程的开始位置和结束位置。但这种方式依赖于硬件,由硬件将虚拟内存地址快速转换为物理地址。理论来说基址寄存器和界限寄存器可以 存储所有进程的起始位置和结束位置,但这样的话首先需要记录的内容变多,而且查找进程的对应开始和结束位置也会变慢,因此实际应用是只会存当前运行的进程的开始和结束位置,之前运行分时结束后 可将运行的开始和结束位置记录到进程控制块内(PCB),等CPU调度下次运行时,在写入到基址和界限内存器当中。这种处理方式的弊端会造成内存空间的浪费,比如说最小分配单位为16KB,有些进程实际根本用不了,就会产生内存碎片,导致资源的浪费。注意这种是连续分配的。
分段
可将程序分成代码、堆、栈三段,每段有基址和界限寄存器记录位置,不用设置最小分配单位,相当于由上一步骤的一整块拆分成了三段,但是可以灵活分配存储空间大小,避免了地址空间的逻辑段之间的大量潜在的内存浪费,分段可以更好的支持稀疏地址管理,分段带来的附加好处:代码共享。如果代码放在独立的段空间内,可以被多个运行的程序共享。但同样的也会带来问题就是外部内存碎片,非程序占用的,因为分配的空间大小和顺序不固定,可能会导致产生许多非连续的未使用内存空间,当需要分配连续的内存空间时,这些内存无法使用就产生了浪费,这时候也有人会提,可以定期进行内存迁移啊,去掉外部内存空间碎片,但这种拷贝段是内存密集型,一般会占用大量的处理器时间。还有一个问题就是跟动态重定位一样,虽然是分成了三部分,但是如果有很大但比较稀疏的堆,仍要全部加载到内存中去,还是做不到很好的内存空间管理。这种是非连续分配方式。地址转换的时候可引入硬件段寄存器,可用14位虚拟地址来区分段以及偏移量。比如前2位区分段,后12位区分具体的偏移量,可参照如下:
分段.png
分页
分页是将空间分割成多个固定的分片,或者说是分割成多个固定的单元,每个单元称为页,一般页的大小为16KB.分页的优点大大提高了灵活性,操作系统可以高效地提供地址空间的抽象,另一个优点就是空闲空间的管理更加便捷简单。 分页是属于硬件层面的,所以要新增虚拟地址和物理分页的映射关系,也称为页表,注意是每个进程都会有页表。页表的引入又带来新的问题,假设一个8G大小的内存,2的三十三次方字节,每个页16KB,2的14次方字节,把页表理解成线性结构或者数据库的一张表,则表数量为2的19次方= 524288,假设每个页项占用4字节(32位),每个程序的页表占用空间即为2M,100个程序占用内存空间即200M。首先第一个缺点:页表占用的空间大。第二:页面检索慢,通过虚拟地址检索出实际的物理地址遍历查看,速度慢。而且一般单个程序也无法全部占用内存空间,全部加载页表也是一种空间浪费。简单来说占用空间大和检索速度慢2大问题。由此又引出了快表和多级页表的概念。注意分配方式是非连续分配,页表维护好映射关系即可。
快表(TLB)
如何才能加速虚拟地址转换,尽量避免额外的内存访问?需要什么样的硬件支持?操作系统该如何支持?
快速地址转换。由硬件支持,放到高速缓存区。物理地址=(页号->块号)+偏移量。
简述:
当计算机程序需要访问内存地址时,处理器需要将程序使用的虚拟内存地址转换为硬件使用的物理内存地址。这个翻译过程可能会耗费很多时间,特别是对于访问许多内存地址的大型程序而言。
为了加快这个过程,处理器使用TLB缓存最近使用的翻译。TLB存储虚拟内存地址和物理内存地址之间的映射,允许处理器快速查找给定虚拟地址的物理地址,而不必执行耗时的翻译过程。
TLB是针对当前正在运行的进程的,当进行进程切换的时候,TLB又该如何工作了呢?
答:当进程切换时,TLB需要清空缓存、加载新进程的页表信息并更新TLB缓存,以确保正确地进行虚拟地址到物理地址的转换。上下文切换的时候清空TLB,这是一个可行的解决方案,进程不会再读到错误的地址映射。但是,有一定开销:每次进程运行,当它访问数据和代码页时,都会触发TLB未命中。如果操作系统频繁地切换进程,这种开销会很高。为了减少这种开销,一些系统增加了硬件支持,实现跨上下文切换的TLB共享。比如有的系统在TLB中添加了一个地址空间标识符(Address Space Identifier,ASID)。因为多个进程共用TLB,所以可共享代码页(以二进制或共享库的方式),即不同进程的虚拟页可以指向相同的物理页,减少物理页的使用,从而减少了内存开销。
多级页表
为解决页表占用空间大且检查速度慢,引入多级页表的概念,
类似于数据库的分库分表,将页表水平拆成多个表,例如二级表。一级页表作为索引表,指向二级表,二级页表作为实际地址映射表。32位的结构可理解如下:
两级页表.png
在一个多级页表系统中,每个进程都有自己的页表,它们在操作系统内存中被存储。一个虚拟地址被分解成多个部分,每个部分被用来索引相应的页表。每个页表项包含一个物理地址或者指向下一级页表的指针,因此可以通过多级索引找到物理地址。
多级页表的优点是可以将页表的大小减小到合理的范围内,同时也可以更高效地进行地址映射。此外,多级页表还可以实现虚拟地址的共享和保护。
段页式管理(补充)
段页式管理将内存分成段和页两个部分,其中每个段可以包含多个页面。这种技术可以更好地管理内存,同时提高系统的效率和灵活性。段页式管理还可以减少外部碎片和内部碎片的问题,提高内存的利用率。
在段页式管理中,每个进程有一个独立的虚拟地址空间,其中包含多个段和页面。段页式管理将虚拟地址空间分成不同的段,每个段可以包含不同数量的页面。当进程需要访问某个地址时,操作系统会将虚拟地址转换为物理地址,然后访问相应的页面。
总之,段页式管理是一种内存管理技术,它将内存分成段和页两个部分,可以更好地管理内存,提高系统的效率和灵活性。段表和页表。
虚拟内存管理
页面置换算法:
-
先进先出(FIFO)算法:选择最先进入内存的页面进行置换。
-
最近最少使用(LRU)算法:选择最近最久未被使用的页面进行置换。
-
最少使用(LFU)算法:选择使用次数最少的页面进行置换。
-
时钟(Clock)算法:将所有页面按照访问位的值分为两类,然后选择访问位值为0的页面进行置换。
-
最不经常使用(NFU)算法:选择使用次数最少的页面进行置换,但是使用次数的统计是按照时间片来计算的,即使用次数在一定时间段内的平均值。
-
最不经常使用的改进(NUR)算法:将页面按照访问位和修改位的值分为四类,然后选择访问位和修改位都为0的页面进行置换。
-
基于工作集的页面置换算法:在程序执行时记录每个页面最近被访问的时间,然后根据工作集的大小来动态调整内存中页面的数量。如果某个页面在工作集中的时间超过了一定的阈值,那么就将其置换出去。
-
最优(OPT)算法:选择在未来最长时间内不会被访问到的页面进行置换。这是一种理论上最优的算法,但是实际中很难实现,因为需要预测未来的访问模式。
页面分配策略
页面分配策略是指操作系统在将程序的虚拟地址映射到物理地址时,如何分配物理页面的策略。下面是一些常见的页面分配策略:
-
固定分配策略:操作系统在程序运行前为程序分配一定数量的物理页面,程序只能使用这些页面,不能再申请新的页面。这种策略可以保证程序的内存使用量不会超过限定值,但是可能会导致浪费。
-
可变分配策略:操作系统根据程序的需要,动态地为程序分配物理页面。这种策略可以使得程序使用内存更加高效,但是需要考虑页面分配的效率和分配策略的复杂度。
-
交换分配策略:当物理内存不足时,操作系统将一部分暂时不使用的页面交换到磁盘上,以释放出物理页面供其他程序使用。这种策略可以在一定程度上扩展物理内存,但是交换过程需要消耗时间和I/O资源。
-
请求分配策略:程序需要内存时,先向操作系统发送请求,由操作系统根据当前内存情况进行分配。这种策略可以使得内存使用更加高效,但是需要操作系统进行调度,增加了系统的开销。
-
共享分配策略:多个程序可以共享同一个物理页面。这种策略可以节省内存空间,但是需要考虑页面的读写权限和页面的同步问题。
页面调入时机
虚拟内存中页面的调入时机可以根据需要进行调整,一般有以下几种情况:
-
预取(Prefetching):虚拟内存可以通过预取技术,在程序需要访问某个页面之前提前将该页面加载到内存中。预取可以提高程序的运行效率和响应速度,因为它可以预先加载一些数据和代码,避免了等待页面调入的时间。
-
页面置换(Page Replacement):当内存中的页面不足时,虚拟内存会将某些页面置换到硬盘上,以腾出内存空间供新页面使用。页面置换的时机通常是在需要加载新页面时,操作系统会根据一定的置换算法选择要置换的页面。
-
冷启动(Cold Start):冷启动是指当程序第一次运行时,需要将其所需的页面全部加载到内存中。在这种情况下,页面调入的时机通常是在程序启动时进行。
MMU
MMU是Memory Management Unit(内存管理单元)的缩写,是计算机中用于管理内存的重要部件之一。它主要负责实现虚拟内存的功能,将逻辑地址(也称虚拟地址)映射到物理地址,从而为操作系统和应用程序提供了一个虚拟的、统一的地址空间。
MMU通过使用地址映射表(Page Table)来实现逻辑地址到物理地址的转换,这个映射表包含了虚拟地址与物理地址之间的对应关系。当CPU访问一个虚拟地址时,MMU会通过查找映射表来确定对应的物理地址,并将该地址发送到内存控制器,最终得到所需的数据或指令。
除了地址映射功能,MMU还可以实现内存保护和共享等功能。通过为每个进程分配独立的地址空间和访问权限,MMU可以确保每个进程都只能访问自己的内存空间,从而提高系统的安全性和稳定性。同时,MMU还可以实现内存共享,多个进程可以共享同一块内存区域,从而减少内存使用量,提高系统效率。
总之,MMU是计算机系统中一个非常重要的组成部分,它为操作系统和应用程序提供了强大的内存管理和保护机制,是现代操作系统和计算机系统中必不可少的技术。