首先先了解下计算机的存储结构:
虚拟内存是借助二级存储空间来扩大一级存储空间的机制。
DRAM是VM系统(虚拟存储器系统)在主存中的缓存,他在主存中用在缓存虚拟页。
SRAM是CPU和主存之间的高速缓冲,CPU从主存中取指。
CPU先在SRAM中查找,如果不命中,则在DRAM中查找,如果再次查找失败,则通过页面置换,从磁盘中读取数据。由于IO操作开销很大,所以DRAM命中失败的开销更大。当CPU需要从磁盘中查找DRAM未命中的数据时,需要借助MMU(内存管理单元)来获取数据在磁盘中的位置,MMU完成物理地址到虚拟地址的转换,数据在磁盘中的地址就是虚拟地址。
数据一般按页存储,一个页面一般是4~8KB。
虚拟地址(VA),假设其范围是[0,1,2......N-1],N=2^n,N的单位为字节,那么这个虚拟地址就叫做一个n位地址空间。32/64位操作系统具有的虚拟内存空间大小分别是2^32和2^64。
虚拟存储器(VM)就是一个存储在磁盘上的N个连续字节大小的单元。每个字节都是一个唯一的虚拟内存地址。操作系统将VM分割成虚拟页大小的块。
物理存储器被分割成物理页(PP),大小也为字节。
虚拟页(VP)有三种状态:
1)未分配虚拟页:在页表中不存在对该虚拟页的记录;
2)已缓存虚拟页:在页表中有记录,且在物理存储器中已经分配了页面;
3)未缓存虚拟页:在页表中有记录,但是没有缓存到物理存储器。
我认为这里的物理存储器就是DRAM。
上面提到了页表,页表是存储在DRAM中的一个数据结构,完成虚拟页到物理页的映射。虚拟存储器/页表/物理存储器之间的映射关系如下:
图中,页表记录了虚拟页VP1,VP2,VP7,VP4在物理存储器中的位置,VP3,VP6在页表中有记录,但是没有缓存到物理存储器。有效位用来记录页表是否缓存到物理存储器。进程被分配的内存都是虚拟内存,当CPU读取进程的数据时,其实就是获取虚拟页的数据的过程,CPU首先通过虚拟地址作为页表的下标索引,找到其在页表中的记录,通过记录获取它在物理存储器中的物理地址,然后读取物理页。
CPU在DRAM中命中失败,叫做缺页。缺页后的一种算法是按需调度算法:
1.从DRAM中选择一个牺牲页;
2.如果牺牲页被修改过,则将其拷贝回磁盘;
3.根据虚拟地址,通过IO操作从磁盘中获取虚拟页,将其拷贝到DRAM中,并更新页表。
磁盘与DRAM之间的页面交换行为叫做页面调度。
程序的时间局部性使得虚拟存储的概念非常好用,所谓的程序时间局部性是指,在某一段时间,程序趋向于重复执行某一段代码。这种特性使得频繁的页面调度不会出现。
每一个进程都有自己独立的虚拟内存空间,多个虚拟页表可以映射到同一物理页面上,具体某一时刻该哪一进程调用,属于系统资源调度问题,分时系统采用时间分片的方式,具体的调度算法在后面的章节中讲述。
每个进程都有相同格式的内存分配,不管代码和数据实际存储在物理存储器的何处,每个linux进程都使用如下格式:
虚拟地址空间从0x0000 0000-0xffff ffff,大致前3G(0x0000 0000-0xbfff ffff)是用户空间,后1G(0xc000 0000-0xffff ffff)是内核空间,只读段存储的应该是程序二进制代码以及文字常量,然后是.data,存储的是已初始化的全局变量,然后再是.bss,存储的是未初始化的全局变量,然后再是堆区,是程序员通过malloc/new来分配内存的地方,通过链表的方式分配内存(堆的分配算法会在后面讲到),从低地址向高地址分配,不连续;再是共享库的存储器映射区域;再是栈区,用来存储函数的参数以及局部变量,从高地址向低地址连续分配;再是用户栈,存储的是命令行参数和环境变量。
操作系统会为进程分配连续的虚拟地址,但是映射到的物理地址并不连续。
虚拟内存的优缺点:
优点
1.虚拟内存机制使得对磁盘的访问得以控制,因为进程被分配的虚拟空间,有区域是只读,有的区域是可读可写,有的区域是不能访问,原本磁盘的访问是任意的,现在编程可控的。
2.虚拟内存机制可以使得进程拥有自己连续独立的空间,进程之间互不干扰。
3.使用有限资源,处理比实际内存更大的文件;
缺点
如果内存严重不足。会引起内存与磁盘的频繁切换,降低性能。
来源:https://blog.csdn.net/qq_36415932/article/details/99692756