操作系统的内存管理主要做什么?
- 负责内存的分配和回收(malloc:申请内存,free:释放内存)
- 将逻辑地址转化为相应的物理地址
分页
分页就是把内存空间划分为大小相等且固定的块,作为主存的基本单位。因为程序数据存储在不同的页面中,而页面又离散的分布在内存中,因此需要一个页表来记录映射关系,以实现从页号到物理地址块号的映射。
访问分页系统中内存数据需要两次的内存访问(一次是从内存中访问页表,从中找到指定的物理块号,加上页内偏移得到实际物理地址;第二次就是根据第一次得到的物理地址访问内存取出数据)。
分段
分页是为了提高内存利用率,而分段是为了满足程序员在编写代码的时候的一些逻辑需求(比如数据共享,数据保护,动态链接等)。
分段内存管理当中,地址是二维的,一维是段号,二维是段内地址;其中每个段的长度是不一样的,而且每个段内部都是从0开始编址。由于分段管理中,每个段内部是连续内存分配,但是段和段之间是离散分配的,因此也存在一个逻辑地址到物理地址的映射关系,相应的就是段表机制。
交换空间
操作系统把物理内存分成一块一块的小内存,每一块内存被称为页,当内存资源不足时,Linux把某些页的内容转移到硬盘上的一块空间上,已释放内存空间。硬盘上的那块空间叫做 **交换空间 **,这一过程被称为交换。物理内存和交换内存的总容量就是虚拟内存的可用容量。
- 物理内存不足时一些不常用的页可以被交换出去,腾给系统。
- 程序启动时很多内存页被用来初始化,之后便不再需要,可以交换出去。
缓冲区溢出
当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入。
常见的内存管理机制
- 连续分配管理方式:为一个用户程序分配一个连续的内存空间。
- 块式管理:远古时期计算机操作系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,成为碎片。
- 非连续分配管理方式:允许一个程序使用的内存分布在离散或者说不相邻的内存中。
- 页式管理:把主存分为几个大小相等且固定的一页一页的形式,页较小,相对于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
- 段式管理:页式管理其中的页没有实际意义。段式管理把主存分为一段一段的,每一段的空间又要比一页的空间小很多,但是最重要的是段有实际意义,每个段定义了一组逻辑信息,例如,有主程序段MAIN、子程序段X、数据段D及栈段S等。段式管理通过段表对应逻辑地址和物理地址。
- 段页式管理:结合了段式管理和页式管理的有点。段页式管理机制就是把主存先分为若干段,每个段有分为若干页,段页式管理中段与段之间及段的内部都是离散的。
快表和多级页表
页表管理机制中有两个概念:快表和多级页表,这
- 虚拟地址到物理地址的转换要快
- 解决虚拟地址孔家大页表也会很大的问题。
快表
为了解决虚拟地址到物理地址转换速度,操作系统在页表方案基础之上引入了快表来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时CPU要访问两次主存。有了快表,有时只需要访问一次高速缓冲存储器,一次主存,这样可以加速查找并提高指令执行速度。
使用快表后地址转换的流程是这样的:
- 根据虚拟地址中的页号查快表
- 如果该页在快表中直接从快表中读取相应的物理地址;
- 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
- 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。
CPU寻址,为什么需要虚拟地址空间
现代处理器使用的是一种称为虚拟寻址的寻址方式。使用虚拟寻址,CPU需要将虚拟地址翻译成物理地址,这样才能访问到的都是物理内存。实际上完成虚拟地址转换为物理地址的硬件是CPU中含有一个被称为内存管理单元(MMU)的硬件。
虚拟内存
虚拟内存是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。
为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,有硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。
页面置换算法
在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。
页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间释放新的缓存数据。
页面置换算法的目标是使页面置换频率最低(也可以说缺页率最低)。
-
最佳算法:所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。是一种理论上的算法,因为无法知道一个页面多长时间不在被访问。
-
先进先出:选择换出的页面是最先进入的页面。将那些经常被访问的页面也被换出,从而使缺页率升高。
-
LRU:
虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU将最近最久未使用的页面换出。
为了实现LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。因为每次访问都需要更新链表因此这种方式实现的LRU代价很高。
-
时钟算法:使用环形链表将页面连接起来,在使用一个指针指向最老的页面。它将整个环形链表的每一个页面做一个标记,如果标记是0,那么暂时就不会被替换,然后时钟算法遍历整个环,遇到标记为1的就替换,否则就将标记为0的替换为1。