无存储设备 最简单的存储器抽象就是根本没有抽象。每一个程序都直接访问物理内存。当一个程序执行如下命令: MOV REGISTER1, 1000 计算机会将位置1000的物理内存中的内存移到REGISTER1中。因此,那时呈献给编程人员的存储器模型就是简单地物理内存:从0到某个上限的地址集合,每一个地址对应一个可容纳一定数目二进制位的存储单元,通常是8个。 一种存储抽象:地址空间 把物理地址暴露给进程会带来几个严重问题:第一,如果用户程序可以寻址内存的每个字节,它们就可以很容易地(故意地或偶然地)破话操作系统;第二,使用这种模型,想要同时(如果只有一个CPU就轮流执行)运行多个程序时很困难的。 地址空间的概念 地址空间为程序创造了一种抽象的内存。地址空间是一个进程可用于寻址内存的一套地址集合。每个进程都有一个自己的地址空间,并且这个地址空间独立于其他进程的地址空间。 交换技术 把所有进程一直保存在内存中需要巨大的内存,如果内存不够,就做不到这一点。 有两种处理内存超载的通用方法。最简单的策略是交换技术,即把一个进程完整调入内存,使该进程运行一段时间,然后把它存回磁盘上,所以当它们不运行时就不会占用内存(尽管它们的一些进程会周期性地被唤醒以完成相关工作,然后就又进入睡眠状态)。另一种策略是虚拟内存,该策略甚至能使进程在只有一部分被调入内存的情况下运行。 有一个问题值得注意,即当进程被创建或换入时应该为它分配多大的内存。 如果大部分进程在运行时都要增长,为了减少因内存区域不够而引起的进程交换和移动所产生的开销,一种可用的方法是,当换入或移动进程时为它分配一些额外的内存。 虚拟内存 虚拟内存的基本思想是:每个进程拥有自己的地址空间,每个空间被分割成多个块,每一个块称作一页或页面。每一页有连续的地址范围。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由于硬件立刻执行必要的映射。当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的指令。 分页 由程序产生的这些地址成为虚拟地址,它们构成了一个虚拟地址空间。 虚拟地址空间按照固定大小划分成称为页面的多干单元,在物理内存中对应的单元成为页框。 页表 虚拟地址到物理地址的映射可以概括如下:虚拟地址被分成虚拟页号(高位部分)和偏移量(低位部分)。 页表的目的是把虚拟页面映射为页框。从数学角度说,页表是一个函数,它的参数是虚拟页号,结果是物理页框号。通过这个函数可以把虚拟地址中的虚拟页面的虚拟页面域被替换成页框域。从而形成物理地址。 分段 一个直观并且通用的方法是在机器上提供多个互相独立的称为段的地址空间。分段存储管理,每一个段都可以独立地增大或减小而不会影响其他的段。 分页和分段的比较
纯分段的实现 分段和分页的实现本质上是不同的:页面是定长的而段不是。 分段和分页结合:Pentium 如果一个段比较大,把它整个保存在内存中可能很不方便甚至是不可能的,因此产生了对它进行分页的想法。这样,只有那些真正需要的页面才会被调入内存。 每个段都看做是一个虚拟内存并对它进行分页,以结合分页的优点(统一的页面大小和在只使用段的一部分时不用把它全部调用内存)和分段的优点(易于变成、模块化、保护和共享)。 Pentium处理器中虚拟内存的核心是两张表,即LDT(局部描述符表)和GDT(全局描述符表)。每个程序都有自己的LDT,但是同一台计算机上的所有程序共享一个GDT。LDT描述局部于每个程序的段,包括其代码、数据、堆栈等,GDT描述系统段,包括操作系统本身。 为了访问一个段,一个Pentium程序必须把这个段装入机器的6个段寄存器的某一个。在运行过程中,CS寄存器保存代码段,DS寄存器保存数据,其他寄存器不太重要。 小结 系统通过交换技术可以同时运行总内存占用超过物理内存大小的多个进程,如果一个进程没有内存空间可用,它将被换到磁盘上。内存和磁盘上的空间可以使用位图或空闲区列表来记录。 现代计算机都有某种形式的虚拟内存。在最简单的形式中,每一个进程的地址空间呗划分为同等大小的块,成为页面,页面可以被放入内存中任何可用的页框中。有多重页面置换算法,其中两个比较好的算法是老化算法和工作集时钟算法。 分段可以帮助处理在执行过程中大小有变化的数据结构,并能简化链接和共享。分段还有利于不同的段提供不同的保护。有时,可以把分段和分页结合起来,以提供一种二维的虚拟内存,Pentium就是这样及支持分段也支持分页的系统。 Linux中的内存管理 每个Linux进程都有一个地址空间,逻辑上有三段组成:代码段、数据段和堆栈段。 代码段包含了形成程序可执行代码的机器指令。它是由编译器和汇编器把C、C++或者其他程序源码转换成机器代码而产生的。 数据段包含了所有程序变量、字符串、数字和其他数据的存储。它有两部分,初始化数据和未初始化数据。 跟代码段不同,数据段可以改变。程序总是修改它的变量。而且,许多程序需要在执行时动态分配空间。Linux允许数据段随着内存的分配和回收而增长和缩短,通过这种机制来解决动态分配的问题。 第三段是栈段。在大多数机器里,它从虚拟地址空间的顶部或者附近开始,并且向下生长。如果栈生长到了栈段的底部以下,就会产生一个硬件错误同时操作系统把栈段的底部降低一个页面。程序并不显式地控制栈段的大小。 当一个程序启动的时候,它的栈并不是空的。相反,它包含了所有的环境变量以及为了调用它而向shell输入的命令行。 Windows Vista内管管理 在Windows Vista系统中,每个用户进程都有它自己的虚拟地址空间。对于x86机器,虚拟地址是32位的,因此,每个进程拥有4GB大小的虚拟地址空间。其中用户态进程的虚拟地址大小为2GB(在服务器器系统中,用户态进程的虚拟地址大小可以配置为3GB)。另外的2GB(或1GB)空间为内核进程所用。 转载请并标注: “本文转载自 linkedkeeper.com ” ©著作权归作者所有 |