CPU能够直接访问的通用存储只有内存和处理器的内置的寄存器。机器指令能够用内存地址做为参数,而不能用磁盘地址做为参数。因此执行指令以及指令使用的数据,应在这些可执行访问的存储设备上,若是数据不在内存中,那么在CPU使用他们以前应把数据移到内存上。
CPU内置寄存器一般能够在一个CPU时钟周期内完成访问,可是对于内存,完成内存的访问可能须要多个CPU时钟周期,这种结果形成的影响就是若是没有数据用于完成正在执行的指令,那么CPU可能将会屡次中断(暂停)。因此须要在CPU和内存之间增长一个高速缓存。
为了确保进程的执行正确,须要为每一个进程分配一块单独的内存空间,从而使进程内存空间保护进程而互相不受到影响。经过两个寄存器,一般为基地址寄存器和界限地址寄存器。基地址寄存器中含有最小的合法的物理内存大小;界限地址寄存器中指定了进程范围的大小。内存空间的保护实现是经过在CPU硬件对在用户模式下产生的地址和寄存器的地址进行比较来完成的。也只有操做系统能够经过特殊的特权指令,才能加载基地址寄存器和界限地址寄存器,由于特权指令只能在内核模式下执行,因此只有操做系统能够加载基地址寄存器和界限地址寄存器。算法
一般程序是做为二进制可执行文件存放在磁盘上的,若是须要执行的话,首先要将程序调入内存并放在进程中。在磁盘上等待调入内存以便执行的进程造成了输入队列。
大多数状况下,用户程序在执行前,须要通过好几个步骤,在这些步骤中,地址可能会有不一样的表示形式。源程序中地址一般使用符号表示,编译器一般将这些符号地址绑定到可重定位的地址。连接程序或加载程序在将这些可重定位的地址绑定到绝对地址。每次绑定都是从一个地址空间到另外一个地址空间的映射。
一般,指令和数据绑定到存储器地址可在沿途的任何一步中进行:缓存
CPU生成的地址一般称为逻辑地址,而内存单元看到的地址(即加载到内存地址寄存器的地址)一般是物理地址。编译时和加载时的地址绑定方法生成相同的逻辑地址和物理地址,可是执行时的地址绑定方案生成不一样的逻辑地址和物理地址。在这种状况下,一般成逻辑地址为虚拟地址。
从虚拟地址到物理地址的运行时映射是由**内存管理单元(MMU)**的硬件设备来完成。用户进程所生成的地址在送交到内存以前,都将加上重定位寄存器的值(基地址寄存器)。而用户程序不会看到真实的物理地址。spa
在以前的进程加载到内存中,是将进程的整个程序和全部数据都加载到物理内存当中,因此进程的大小受限于内存的大小,为了得到内存空间利用率,能够采用动态加载。采用动态加载时,一个程序只有在调用时才会加载,全部程序都以可重定位加载格式保存在磁盘中。主程序被加载到内存并执行,当一个程序须要调用另外一个程序时,调用程序首先检查另一个程序是否已经加载到内存中。若是没有,可重定位连接程序会加载所需的程序到内存中,并更新程序的地址表以反映这个变化,接着控制传递给新加载的程序。因此,动态加载的好处就是,只有一个程序须要时才会被加载。操作系统
动态连接库是系统库,可连接到用户程序,以便运行。
若是是静态连接的话,它的系统库与其余目标模块同样,经过加载程序被合并到二进制程序映像。可是动态连接库相似动态加载(注意在这里不是加载而是连接),会延迟到运行时。
若是有动态连接,在二进制映像中,每一个库程序的引用都有一个存根。存根是一小段代码,用来支出如何定位适当的内存驻留库程序,或者在程序不在内存时应如何加载库。当执行存根时,他首先检查所需程序是否已经在内存中,若是不在,将程序加到内存中。存根会用程序地址来代替本身,并开始执行程序,因此下次在执行程序代码的时候,就能够直接进行,而不会因动态连接产生任何开销。blog
进程必须在内存中以便执行,可是,进程能够短暂的从内存交换到备份存储,当再次执行时在调回到内存中。排序
标准交换在内存和备份存储之间移动进程,备份存储一般是快速磁盘。备份存储应该足够的大,以容纳全部用户的全部内存映像的副本,而且应提供对这些存储器映像的直接访问。系统维护一个可运行的全部进程的就绪队列,他们的映像在备份存储和内存中,当CPU调度器决定要执行一个进程时,它调用分派器。分派器检查队列中的下一个进程是否在内存中,若是不在且没有空闲内存区域,那么分派器会换出当前位于内存的一个进程并换入所需进程,而后从新加载寄存器,并将控制权给所选进程。队列
移动系统一般不支持任何形式的交换,移动设备一般采用闪存,而不是空间更大的硬盘做为他的永久存储。苹果的IOS和谷歌的Android的具体交换策略能够自行百度。进程
连续内存分配是早期OS所采用的一种内存分配策略,在采用连续内存分配时每一个进程位于一个连续的内存区域,与包含下一个进程的内存相连。图片
为了放置进程访问不属于他们的内存,依旧经过重定位寄存器和界限寄存器来实现保护,MMU经过动态的将逻辑地址加上重定位寄存器的值。当CPU调度器选择一个进程来执行时,做为上下文切换工做的一部分,分派器会用正确的值来加载重定位寄存器和界限寄存器。因为CPU所产生的每一个地址都须要与这些寄存器进行核对,因此能够保证操做系统和其余用户的程序和数据不受该运行进程的影响。内存
最简单的内存分配方法,就是将内存分为多个固定大小的分区。每一个分区能够只包含一个进程。因此多道程序的程度受限于分区数。
对于可变分区方法,操做系统维护一张表,用于记录哪些内存可用和哪些内存已用。开始时全部内存均可用于用户进程,所以能够做为一大块的可用内存,称为孔。最后内存有一个集合,以包含各类大小的孔。
一般可用的内存块为分散在内存里的不一样大小的孔的集合。当新进程须要内存时,系统为该进程查找足够大的孔。若是孔太大,那么就分为两块:一块分给进程,一块返回孔集合。这种方法是通用动态存储分配问题的一个例子。从一组可用孔中选择一个空闲孔的最经常使用方法有:
用于内存分配的首次适应和最优适应算法都会有外部碎片。对于内存的碎片能够是内部碎片,也能够是外部的。好比假设有一个18464字节大小的孔,有一个进程须要18462字节,若是只能分配所要求的块,那么还剩下2字节的孔。所以一般按固定大小的块为单位来分配内存,采用这种方法,进程所分配的内存可能比所须要的大,这两个数字之差称为内部碎片,这部份内存存在于分区内部,可是又不能用。
外部碎片的一种解决方法是紧缩,移动内存内容,以便将全部的空闲空间合并成一整块。可是紧缩并非老是可能的。若是重定位是静态的,而且在汇编时或加载时进行的,那么就不能紧缩;只有重定位是动态的,且在运行时进行的,那么才能够采用紧缩。