先给文章定个位,主要是总结一下虚拟内存,以便自己复习。具体的case参考csapp(感谢360的面试官推荐的书)。如果有错误,还望不吝赐教。
csapp总结虚拟内存有三个作用:
1.作为磁盘的缓存:
为了区分cpu与主存之间的缓存,下文称cpu与主存之间的为高速缓存。磁盘的缓存仍称为虚拟内存。而缓存指代两者。尽管都作为缓存,虚拟内存和高速缓存的起因,并不是一样的,高速缓存一开始就是为了加快速度的,而虚拟内存是因为多用户多任务(个人见解,无出处,请酌情参考)。但同为缓存,使命是一样的,增加命中率。组织方式也是有共同点的,虚拟内存和高速缓存的区别在于组相连数,虚拟内存采用的是全映射。有高速缓存的基础,我本能的觉得,高速缓存是用map保存虚拟页和物理页的映射关系。然后,事实是,数组,也就是传说中的页表。
页表,以虚拟页编号为索引,数组内部放的是物理页号。用数组有两个问题。其一,页表放在内存里,增加了内存的访问次数,增加了时间的消耗。其二,虚拟内存挺大的2^48,需要很大的数组才能放下所有页表项。 解决方案:一、用硬件加速TLB,二、多级页表。第一很容易理解,第二,多级页表实际上不能减少页表的空间消耗,如果一个进程使用了所有虚拟空间。但是,这个 如果 一般都不成立,所以,多级页表就有用了。
2.内存管理工具:
在这个方面,虚拟内存提供了四个东西:共享(linux's kernel same-page merging,mmap);给进程统一的组织方式,见下图,图片来源csapp课件;写时复制,省去大量的拷贝,代表函数 fork;demand paging,计算机懒惰机制的又一实现,代表函数 execve。(个人见解,无出处,请酌情参考)
fork和execve的区别在于,fork函数要指向的页面有可能已经在内存里了,两个进程同时访问一份数据,如果只是读,没问题,重点是,如果要写,怎么办? 写时复制就是,你读我不管,你写我就拷贝出另一份来;execve要访问的页面,完全在磁盘,所以就,直接把页表改改,用demand paging手段,等真的要访问了,才加载进内存。
3.内存保护工具
以前看书的时候,说现在的操作系统是段页式内存管理,看上面的用法完全是页式。感觉有点段式的是,mm结构体,在段上提供了数据保护。带权限标志的页表则在页上提供了数据保护。
mm结构体是由程序段的相关信息构成的链表,为了加快搜索速度,又在链表上构建了树。