Linux虚拟存储器系统
在了解了虚拟存储器的相关知识之后,我们通过Linux的虚拟存储器系统,来大致了解下操作系统是如何组织虚拟存储器的。
Linux进程的虚拟存储器
上图是一个Linux进程的虚拟存储器,与之前所示虚拟存储器的区别在于,其展现方式不再是一个个独立的页,而是按照不同的功能组织成不同的区域。区域
Linux将虚拟存储器组织成一些区域的集合。一个区域就是已分配的虚拟存储器的连续片,这些页是以某种方式相关联的。每个存在的虚拟页面都保存在某个区域中,而不属于某个区域的虚拟页是不存在的,并且不能被进程引用。内核为系统中的每个进程维护一个单独的任务结构。任务结构中的元素包含或者指向内核运行该进程所需要的所有信息(例如,PID、指向用户栈的指针、可执行目标文件的名字以及程序计数器)。
task_struct中的一个条目指向mm_struct,它描述了虚拟存储器的当前状态。其中pgd指向第一级页表(页全局目录)的基址,而mmap指向一个vm_area_struct(区域结构)的链表,其中每个vm_area_struct都描述了当前虚拟地址空间的一个区域(area)。缺页处理
这里着眼点在于如何结合Linux的虚拟存储器结构进行缺页处理。当MMU翻译某个虚拟地址触发缺页时,则异常导致控制转移到内核的缺页处理程序,程序执行以下步骤:- 判断虚拟地址是否合法,即是否在区域结构定义的区域内。
- 判断试图进行的存储器访问是否合法,即判断进程是否有读、写或执行这个区域内页面的权限。
存储器映射
Linux虚拟存储器通过将虚拟存储器区域与一个磁盘上的对象关联起来,以初始化这个虚拟存储器区域的内容,这个过程称为存储器映射。
虚拟存储器区域可以映射到两种类型的对象中的一种:- Unix文件系统中的普通文件:一个区域可以映射到一个普通磁盘文件的连续部分,例如一个可执行目标文件。
- 匿名文件:匿名文件是由内核创建的,包含的全是二进制零。CPU第一次引用这样一个区域内的虚拟页面时,内核就在物理存储器中找到一个合适的牺牲页面,用二进制零覆盖牺牲页面并更新页表,将这个页面标记为是驻留在存储器中的。在磁盘和存储器之间并没有实际的数据传送。映射到匿名文件的区域中的页面有时也叫做请求二进制零的页。比如堆栈、未初始化的数据区域等,与磁盘无关了其实。
共享对象
一个对象可以被映射到虚拟存储器的一个区域,要么作为共享时象,要么作为私有对象。对私有对象的写操作不会反应在磁盘上的对象中,而对共享对象的写操作会。
私有对象使用一种写时拷贝技术,即在未进行写操作时,多个进程的虚拟存储器指向同一个对象,知道某个进程进行了写操作才拷贝一份。
execve函数
execve函数在当前进程中加载并运行包含在可执行目标文件a.out中的程序,用a .out程序有效地替代了当前程序。加载并运行a .out需要以下几个步骤:- 删除已存在的用户区域。
- 映射私有区域。
- 映射共享区域。
- 设置程序计数器。