物理寻址和虚拟寻址
使用虚拟寻址时,CPU通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到存储器之前先转换成适当的物理地址。将一个虚拟地址转换为物理地址的任务叫做地址翻译。地址翻译需要CPU硬件和操作系统之间的紧密合作。CPU芯片上叫做存储器管理单元的专用硬件,利用存放在主存中的查询表来动态翻译虚拟地址,该表的内容是由操作系统管理的。
地址空间
一个地址空间的大小是由表示最大地址所需要的位数来描述的。一个包含N=2^n个地址的虚拟地址空间就叫做一个n位地址空间。现代操作系统典型的支持32位或者64为虚拟地址空间。一个系统还有一个物理地址空间,它与系统中物理存储器的M个字节相对应。
虚拟内存的作用
使用虚拟内存有许多的好处,操作系统其实为每个进程提供了一个独立的页表,使用不同的页表也就创建了独立的虚拟地址空间。使用虚拟内存可以简化链接、简化加载、简化共享、简化存储器分配、简化保护。
地址翻译
命中的地址翻译过程
1.处理器生成虚拟地址 VA,传给 MMU;
2.MMU 生成 PTE 地址,通过高速缓存或主存请求得到它;
3.高速缓存或主存返回PTE;
4.MMU 构造物理地址,并传送给高速缓存或主存;
5.高速缓存或主存返回请求的数据字给处理器。
不命中的地址翻译过程
1.处理器生成虚拟地址 VA,传给 MMU;
2.MMU 生成 PTE 地址,通过高速缓存或主存请求得到它;
3.高速缓存或主存返回PTE;
4.PTE 有效位为 0,传递 CPU 的控制,让操作系统内核执行缺页异常处理程序
5.确定物理内存的牺牲页,如果该牺牲页已被修改则换出磁盘;
6.缺页处理程序页面调入新的页面,并更新内存中的 PTE。
7.返回到原来的进程,再次执行缺页指令,此时会命中,MMU 将返回请求的数据字给处理器。
内存映射
内存映射是指将磁盘上的一个文件与虚拟存储器中的一个区域关联起来的这个过程。
共享对象
一个对象被映射到虚拟存储器的一个区域,这个区域要么是共享对象,要么是私有对象。如果一个进程A将一个共享对象映射X到了它的虚拟存储器中,那么对于同时也映射了这个共享对象X的其他进程而言,进程A对共享对象X的任何读写操作都是可见的。对于一个映射到私有对象的区域做的改变,对于其他进程来说是不可见的,并且进程对这个区域所做的任何写操作都不会反映在磁盘上的对象中。
每个对象都有唯一的一个文件名,在进程1的虚拟存储器中已经完成了私有对象到存储器的映射,进程2如果要映射这个区域只需要将页表条目指向已经映射好的物理存储器位置就行了。如上图所示,进程1和2将一个私有对象映射到了物理存储器的一个区域并共享这个私有对象。这个对象会被标记为只读,当其中一个进程2确实需要写这个区域的时候,就会引发一个保护故障,内核会在物理存储器中创建这个私有对象的一个拷贝,称为写时拷贝,更新页面条目使得进程1指向这个新的条目。然后把老对象修改为可写权限。这样当保护故障程序返回的时候,CPU从新执行写的操作就不会出错了。
fork函数如何创建独立的虚拟地址空间
一个进程调用fork函数的时候,内核为新进程创建各种数据结构,并分配PID。为了给新进程创建一个虚拟存储器,它创建的当前进程的mm_struct、区域结构和页表的一个拷贝,内核为两个进程的每个页表标记为只读,并将诶个区域标记为私有的写时拷贝。这样当fork函数返回的时候,新进程的虚拟存储器和当前进程的虚拟存储器刚好相同。任何一个进程进行写操作的时候,才会创建新的页面。
execve函数实际上如何加载和执行程序
1.删除已存在的用户区域;
2.映射私有区域
3.映射共享区域;
4.设置程序计数器。
使用mmap函数创建新的存储器映射
mmap函数要求内核创建一个新的虚拟内存区域,从地址start开始处创建,并将文件描述符fd指定的对象的一个连续的片映射到这个新的区域。