一 概述:
虚拟内存作为一种逻辑层,处于应用程序的内存请求和硬件内存管理单元(Memory Management Unit,MMU)之间。
虚拟内存的优点:
应用程序所需内存大于物理内存时也可以运行;
程序只有部分代码装入内存时进程就可以执行它;
程序是可重定位的,也就是说,可以把程序放在物理内存的任何地方;
程序员可以编写与机器无关的代码,因为他们不必关心有关物理内存的组织结构。
虚拟内存子系统的主要成分是虚拟地址空间(virtual address space)。进程所使用的一组内存地址不同于物理内存地址。当进程使用一个虚拟地址时,内核和MMU协同定位其在内存中的实际物理位置。
所有unix系统都将RAM分为两个部分:
1.其中若干兆字节专门用于存放内核映像(即内核代码和内核静态数据结构)
2.RAM的其余部分通常由虚拟内存系统来处理,满足一下三种可能的方面:
&满足内核对缓冲区、描述符以及其他动态内核数据结构的请求;
&满足进程对一般内存区的请求及对文件内存映射的需求;
&借助于高速缓存从磁盘或其他缓冲设备获得较好的性能
内核内存分配器(kernel Memory Allocator,KMA):
内核内存分配器是一个子系统,它试图满足系统中所有部分对内存的需求(来自其他内核子系统,它们需要一些内核使用的内存,还有一些来自用处程序的系统调用,用来增加进程的地址空间)。
一个好的KMA的特点:
&必须快,最重要的属性,因为它由所有的内核子系统调用;
&必须把内存的浪费减少到最低;
&必须努力减轻内存的碎片问题;
&必须与其他内存子系统合作,以便借用和释放页框。
进程的虚拟地址空间:
进程的虚拟地址空间包括了进程可以引用的所有虚拟内存地址。内核通常用一组内存区描述符描述进程虚拟地址空间。
内核分配给进程的虚拟地址空间由以下内存区组成:
&程序的可执行代码;
&程序的初始化数据;
&程序的未初始化数据;
&初始程序栈(用户态栈);
&所需共享库的可执行代码和数据;
&堆(由程序动态请求的内存)
所有现代unix操作系统都采用请求调页(demand paging)的内存分配策略。有了请求调页,进程可以在它的页还没有在内存是就开始执行。当进程访问一个不存在的页时,MMU产生一个异常;异常处理程序找到受影响的内存区,分配一个空闲的页,并用适当的数据把它初始化。同理,当进程调用malloc或brk(由malloc在内部调用)系统调用动态请求内存时,内核仅仅修改进程的堆的大小。只有试图引用进程的虚拟内存地址而产生异常时,才给进程分配页框。
物理内存的一个优势是作为磁盘和其他块设备的高速缓存。尽可能的推迟写磁盘的时间,因此,从磁盘读入内存的数据即使任何进程不再使用它们,它们也继续呆在RAM中。这一策略的前提:新进程请求从磁盘读写的数据,就是被撤销进程所拥有的数据。
当一个进程请求访问磁盘时,内核首先检查进程请求的数据是否在缓存中,如果在(缓存命中),内核就可以为进程提供服务而不用访问磁盘。
sync()系统调用来把所有“脏”的缓冲区(即缓冲区的内容与对应磁盘块的内容不一样)写入磁盘来强制磁盘同步。为了避免数据丢失,所有的OS都会注意周期的把脏缓冲区写回磁盘。
|