第九章 虚拟存储器

                《1》虚拟存储器提供了三个重要的能力:

                          1.它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效的使用主存。

                         2. 它为每个进程提供了一致的地址空间,从而简化了存储器管理。

                         3.它保护了每个进程的地址空间不被其他进程破坏。它成功的一个主要原因就是因为它是沉默地,自动地工作的,不需要应用程序员的任何干涉。

                《2》使用虚拟地址寻址,CPU通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到存储器之前先转换成适当的物理地址。将一个虚拟地址转换为物理地址的任务叫做地址翻译。CPU芯片上叫做存储器管理单元(MMU)的专用硬件,利用存放在主存中的查询表来动态翻译虚拟地址,该表的内容是由操作系统管理的。

                《3》虚拟存储器被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每字节都有一个唯一的虚拟地址,这个唯一的虚拟地址是作为到数组的索引的。磁盘上数组的内容被缓存在主存中。和存储器层次结构中其他缓存一样,磁盘(较低层)上的数据被分割成块,这些块作为磁盘和主存(较高层)之间的传输单元。VM系统通过将虚拟存储器分割成虚拟页(Virtual Page , VP)的大小固定的块来处理这个问题。每个虚拟页的大小为P=2^p 字节。类似地, 物理存储器被分割成物理页(Physical Page , PP), 大小也为P字节(物理页也称页帧(page frame))。在任意时刻,虚拟页面的集合都分为三个不相交的子集:未分配的:VM系统还未分配(或者创建)的页。未分配的块没有任何数据和它们相关联,因此也就不占用任何磁盘空间。缓存的:当前缓存在物理存储器中的已分配页。未缓存的:没有缓存在物理存储器中已分配页。

                《4》页表就是一个页表条目(Page Table Entry , PTE)的数组。虚拟地址空间中的每个页但在页表中一个固定偏移量处都有一个PTE。为了我们的目的,我们假设每个PTE是由一个有效位和一个n位地址字段组成的。有效位表明了该虚拟页当前是否被缓存在DRAM中。如果设置了有效位,那么地址字段就表示DRAM中相应的物理页的起始位置,这个物理页中缓存了该虚拟页。如果没有设置有效位,那么一个空地址表示这个虚拟页还未被分配。否则,这个地址就指向该虚拟页在磁盘上的起始位置。

                                                                                                    

到目前为止,我们都假设有一个单独的页表,将一个虚拟地址空间映射到物理地址空间。实际上,操作系统为每个进程提供了一个独立的页表,因而也就是一个独立的虚拟地址空间。

虚拟地址偏移量VPO与物理页面偏移量PPO是相等的。

                 《5》Linux将虚拟存储器组织成一些区域(也叫做段)的集合。一个区域(area)就是已经存在着的(已分配的)虚拟存储器的连续片(chunk),这些页是以某种方式相关联的。

  一个Linux进程的虚拟存储器:

                                                                                

Linux是这样组织虚拟存储器的:


task_struct 中的一个条目指向mm_struct,它描述了虚拟存储器的当前状态。我们感兴趣的两个字段是pgd和mmap,其中pgd指向第一级页表(页全局目录)的基址,而mmap指向一个vm_area_structs(区域结构)的链表,其中每个vm_area_structs都描述了当前虚拟地址空间的一个区域。具体区域的结构包含下面的字段:

vm_start :指向这个区域的起始处。

vm_end: 指向这个区域的结束处。

vm_port : 描述这个区域内包含的所有页的读写许可权限。

vm_flags:描述这个区域内的页面时与其他进程共享的,还是这个进程私有的(还描述了其他的一些信息)。

vm_next:指向链表中的下一个区域结构。

                   《6》Linux(以及其他一些形式的Unix)通过将一个虚拟存储器区域与一个磁盘上的对象(object)关联起来。以初始化这个虚拟存储器的内容,这个过程称为存储器映射(memory mapping)。一个对象可以被映射到它的存储器的一个区域,要么作为共享对象,要么作为私有对象。如果一个进程将一个共享对象映射到它的虚拟地址空间的一个区域内,那么这个进程对这个区域的任何写操作,对于那些也把这个共享对象映射到它们虚拟存储器的其他进程而言也是可见的。而且,这些变化也会反映在硬盘上的原始对象中。另一方面,对一个映射到私有对象的区域做的改变,对于其他进程来说是不可见的,并且进程对这个区域所做的任何写操作都不会反映在磁盘上的对象中。

                    《7》私有对象是使用一种叫做写时拷贝(copy-on-write)的巧妙技术被映射到虚拟存储器中的。一个私有对象开始生命周期的方式基本上与共享对象的一样,在物理存储器中只保存有私有对象的一份拷贝。如果两个进程将一个私有对象映射到它们虚拟存储器的不同区域,但是共享这个对象同一个物理拷贝,对每个映射私有对象的进程相应私有区域的页表条目都被标记为只读,并且区域结构被标记为私有写时拷贝。只要没有进程试图写自己的私有区域,它们都可以继续共享物理存储器中对象的一个单独拷贝。

一个私有的写时拷贝对象示例如下:


当只要有一个进程试图写私有区域的某个页面,那么这个写操作就会触发一个保护故障,当故障处理程序注意到保护异常是由于进程试图写私有的写时拷贝区域中的一个页面而引起的,它就会在物理存储器中创建这个页面的一个新拷贝,更新页表条目指向这个新的拷贝,然后恢复这个页面的可写权限。

                     《8》当fork函数被调用的时候,内核为新进程创建各种数据结构,并分配给它一个唯一的PID。为了给这个新进程创建虚拟存储器,它创建了当前进程的mm_struct,区域结构和页表的原样拷贝。它将两个进程中的每个页面都标记为只读,并将两个进程中的每个区域结构都标记为私有写时拷贝。

                     《9》动态存储器分配器维护着一个进程的虚拟存储器区域,称为堆(heap)

                                                                                                                   

分配器有两种基本风格:显示分配器,要求应用显示地释放任何已分配的块。 C程序通过调用malloc函数来分配一个块,并通过调用free函数来释放一个快。C++的new和delete操作符与C中的malloc和free相当。隐式分配器:要求分配器检测一个已分配块何时不再被程序所使用,那么就释放这个块。隐式分配器也叫做垃圾收集器。

                    《10》malloc不初始化它返回的存储器。想要已初始化的动态存储器的应用程序可以使用calloc, calloc是一个基于malloc的瘦包装函数,它将分配的存储器初始化为零。想要改变一个以前已经分配块的大小,可使用realloc函数。

                    《11》可以通过sbrk函数来扩展和收缩堆:

            #include<unistd.h>

     void *sbrk(intptr_t incr);   sbrk函数通过将内核的brk指针增加incr来扩容和收缩堆。如果成功,它就返回brk的旧值,否则返回-1,并将errno设置为ENOMEM。如果incr为零,那么sbrk就返回brk的当前值。用一个负的incr来调用sbrk是合法的,而且很巧妙,因为返回值(brk的旧值)指向距离新堆顶向上abs(incr)字节处。

                    《12》造成堆利用率很低的主要原因是一种称为碎片的现象,当虽然有未使用的存储器但不能用来满足分配请求时,就会发生这种现象。有两种形式的碎片:内部碎片和外部碎片。内部碎片是在一个已分配块比有效载荷大时发生的。外部碎片是当空闲存储器合计起来足够满足一个分配请求,但是没有一个单独的空闲块足够大可以用来处理这个请求发生时发生的。一个简单的碓块格式:


                  《13》C程序中常见的与存储器有关的错误:

             间接引用坏指针, 读未初始化的存储器, 允许栈缓冲区溢出, 假设指针和它们指向的对象是相同大小的, 造成错位错误, 引用指针,而不是它所指向的对象, 引用不存在的变量, 引用空闲块中的数据, 引起存储器泄漏。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值