在单任务计算机系统里,主存被划分为两块:一块装操作系统(内核),一块装应用程序。系统主存被单一的应用进程独占,没有存储管理的需求。但在多任务计算机系统上,装应用程序的那块主存则必须进一步划分数块,一块装一个应用程序。操作系统负责动态划分主存,分配主存给应用程序和回收应用程序释放的主存,这个任务叫存储管理(memory management)。负责管理存储器的操作系统子系统,我们称之存储管理子系统,统称[存储管理机]。
[存储管理机]的管理效率关系到整个多任务系统的性能。例如,如果系统主存只能装少量几个应用程序,而当主存中全是需频繁读写慢速IO设备的应用程序时,CPU频繁被闲置的同时,可能有其它就绪的应用程序因为没有被装入主存而被闲置,CPU资源没有被得到高效利用。
存储管理需求
无论计划设计或正在设计一项产品,我们务必时刻紧记产品所满足的需求(requirements),根据需求来考虑更好的设计策略。现代多任务计算机系统应用对操作系统的[存储管理机]设计提出以下一些需求:
进程移动
在多任务计算机里,多个进程共享系统可用的主存。通常情况下,程序员在开发程序的时候不可能对程序实际运行在主存时的情况作任何假设,例如程序被具体装入到主存哪里,主存其它位置有什么进程等;
另外,为了最大化CPU的利用率,系统需要利用辅存(主要是磁盘)开辟一块的进程池(pool of ready processes),将阻塞的进程调出主存,将就绪的进程调入主存。当进程被调出主存后,我们很难知道它何时被再次调入,因为它必须被调入回原来的主存位置。然而这种静态置换是低效的。
综合以上两个需求,我们需要某种移动进程(或者叫重定位relocation)的技术,可以将进程移动到主存任意位置。这让我的关注点转移到进程对象运行时的存储结构上来,如下图:
此图展示了一支进程的存储结构。为了简化描述,我们假设进程被装入一块连续的主存区。由存储结构可知,操作系统必须知道
进程地址有,
进程除了以上的结构性地址,程序内部的指令序列还有很多内存引用地址。例如,分支指令(语句)包含了下一条指令的地址;数据引用指令包含了数据字节(或字)的地址。
由上可推得,为了满足进程地址重定位的最直观方案就是,以进程为单位移动,进程内统一使用某种逻辑地址(例如相对地址),逻辑地址在执行时再由CPU硬件和操作系统转为物理地址。
虚拟存储
以进程为单位移动和管理存储,所得效率还是有限的。如果能将移动的单位深入到进程内部,将不常用的部分暂时移出主存,存储管理效率将会更高。这就向存储管理提出更高级的管理需求——进程内部存储管理。
在多任务技术发展的初期,程序员们曾经开发一种【前内存管理系统】——覆盖系统(overlay system)来实现内部存储管理的问题。因为那个时候操作系统还没有出现,程序员通过显式编码来实现overlay system。程序员把程序划分为不同的段(sections),每个段都会被整个载入主存执行一段时间。随着程序的运行推进,新的程序段会被载入,替换已经不需要的程序段。
内部存储管理的任务原是程序开发者的职责,但出于以下两个原因,管理任务还是收归给系统:
第一,开发者对程序的行为是了解的,但是存储管理毕竟不是解题相关的任务,由开发者实现存储管理,第一,分裂的开发者的角色,第二,增加了开发者的劳动;
第二,某些程序动态性过强,开发者不容易预测。
现代计算机系统统统实现了虚拟存储技术来满足进程内部存储管理需求。虚拟存储技术的核心是[虚拟存储器]的概念。虚拟存储器不是主存,也不是外存,而是操作系统和CPU利用二者实现的抽象的存储器,它的功能与主存一样,但是比主存要慢。虚拟存储技术假想将进程载入虚拟存器上运行,主存是虚拟存器的缓存,进程的常用代码和数据缓存在主存上。
要为进程虚构一个虚拟存储器,并且以主存为缓存,那么存储管理机必须负责管理缓存的[命中]和[不命中]处理,前者就是分页技术中用页表来实现虚实地址转换,后者就是分页技术中缺页处理。
进程隔离保护
在多任务的环境,每支进程都必须彼此隔离独立。为了避免进程间产生有意或无意相互干扰——某一进程在没有得到允许的情况下读写其它进程所分配的主存空间,操作系统有责任窃查进程行为。由于进程行为都表现对主存的访问,因此进程行为的检查归为存储管理,而不是进程管理。
从某种意义上说,[进程移动]与[进程保护]是对立的,进程重定位实现增加了进程保护的难度。由于[进程重定位],进程在主存中的位置变得不可预知,不可能在编译时检查绝对地址来实现保护。此外,很多高级语言支持在运行时动态计算来获得数据对象的地址,例如,C语言。
进程保护的可行办法是对进程运行时产生的所有地址进行检查,确保它们只访问属于自己的地址空间。可是,操作系统无法对进程的主存引用操作作全面的检查,光有操作系统(软件)是不够的,储存管理要实现[进程保护],必须得到CPU(硬件)支持。
幸运的是,现代处理器实现了强大的地址硬件,[进程移动]与[进程保护]同时得到实现。
在多任务的环境下,多个进程共享数据的例子有:
第一,同一程序的多个进程实例可共享一份只读的代码;
第二,两支协作进程可共享一份数据来实现通信协作;
第三,基于同一个代码库,如标准C库,编写的多个进程可共享一份库代码,大大节省存储空间。
Any protection mechanism must have the flexibility to allow several processes to
access the same portion of main memory. For example,
if a number of processes are
executing the same program, it is advantageous to allow each process to access the
same copy of the program rather than have its own separate copy.
Processes that are cooperating on some task may need to share access to the same data structure.
The memory management system must therefore allow controlled access to shared
areas of memory without compromising essential protection. Again, we will see that
the mechanisms used to support relocation support sharing capabilities.
one-dimensional, address space, consisting of a sequence of bytes or words. Sec-
ondary memory, at its physical level, is similarly organized.
无论从概念上还是物理实现上,计算机主存都是线性的,无结构的。但是程序是有一定结构的,如一般程序有只读的代码段和可读写的数据段;进程运行时有一部分代码是常用的,有些则很少使用等。如果存储管理能以程序模块为位进行管理,而不整个程序,那么以下的一些需求将得到满足:
第一,程序模块可是单独编写和编译,并且可以在运行时动态链接和加载;
第二,进程保护可以以模块为单位;
第三,进程共享可以以模块为单位。
While this organization
closely mirrors the actual machine hardware, it does not correspond to the way in
which programs are typically constructed. Most programs are organized into modules, some of which are unmodifiable (read only, execute only) and some of which contain data that may be modified.
If the operating system and computer hardware
can effectively deal with user programs and data in the form of modules of some
sort, then a number of advantages can be realized:
1. Modules can be written and compiled independently, with all references from
one module to another resolved by the system at run time.
2. With modest additional overhead, different degrees of protection (read only,
execute only) can be given to different modules.
3. It is possible to introduce mechanisms by which modules can be shared among
processes. The advantage of providing sharing on a module level is that this
corresponds to the user’s way of viewing the problem, and hence it is easy for
the user to specify the sharing that is desired.
The tool that most readily satisfies these requirements is segmentation, which is one
of the memory management techniques explored in this chapter.
b.创新不是一个跳跃式灵动的结果,创作过程是对既有的经验的思维操作,最常见的操作是对比操作。由此可得,技术化创新(半自动化创新)的一种方法是让对比思维更方便。
b.如果创新是对已有经验和新经验类比出新idea,那么技术化创新的另一些方法包括,第一,丰富已有经验,让类比更有可能性;第二,掌握对已有经验有清晰科学的分类能力。
存储管理机管理设计
划分主存的方式决定了存储管理机的类型,各种类型的优点与缺点都不同,适用于不的计算机应用系统。固定实存分配不适于通用PC,但非常适合用于嵌入式单机系统,因为它调度算法简单高效。
现今大部分的现代多任务操作系统实现了非常复杂的虚拟储存技术。虚拟储存技术的实现基于如下两种技术中一种或两种:分段技术和分页技术。要掌握复杂的虚拟储存技术,我必须从零开始,了解储存管理技术发展历史。
根据实现[进程移动]时的地址翻译的难度,存储管理机分为[一次翻译的实存管理]和[二次翻译的虚存管理]两大类。在大类内又可根据[主存框]的类型进一步细分。
根据进程分配粒度,实存管理分为静态和动态实存; 静态实存管理按进程为单位进行分配和调度,并且主存框的划分是固定的(起始地址固定);根据主存框的[大小是否相等],静态实存管理机有[固定块式实存管理机]和[不定块实存管理机]两个变种。
动态实存主要有页式实存管理机和段式实存管理机两类。页框是大小固定的,段框则大小不一。
实存管理现在已经很少使用,由于它的实现比较原始,更好展示存储管理原理,对理解虚存管理有帮助;
虚存管理为了实现更灵活的存储管理,需要二次地址翻译——一张中间数据表提供翻译信息,例如页表。虚存管理设计的[主存框]类型主要有页和段,相应的存储管理机分别称为[页式虚存管理机]和[段式虚存管理机]。
实存管理机
1.静态实存管理机
1.1固定块式实存管理机
1.2不定块式实存管理机
2.动态实存管理机
2.1页式实存管理机
2.2段式实存管理机
虚存管理机
1.页式虚存管理机
2.段式虚存管理机
[固定块式实存管理机]优点是,第一,因为[主存框]大小和位置都是固定的,所以Placement算法很简单;第二,主存容纳进程的数量是固定的,Replacement算法也比较简单;缺点是,如果进程太大(超过[主存框]大小)则必须手动管理——主程序中有部分代码用来管理内存(如将部分代码或者调入调出),增加USER开发者劳动;如果太小,产生[内部碎片]——主存框没有装满,但也不能再被利用;[固定块式实存管理机]缓解(但不能解决)这两个不足。
[动态实存管理机]很好的解决了手动管理和内部碎片,但会产生[外部碎片]——主存没有装满,但剩余空间因不足再装一个新进程而不能再被利用。外部碎片必须重新回收——移动主存上的进程来合并碎片——才能再用,直接的结果,第一,增加系统开销;第二,增加开发技术难度(增加OS开发者劳动),因为进程必须能重定位才能移动。
由于[动态实存管理机]的[主存框]大小是不固定的,Placement算法相对复杂,因为如果有多块可用的[主存框]时,必须先决定装入哪块[主存框],常用的选择算法有Best-fit 、First-fit 和Next-fit。
实存管理机基本实现了进程移动、进程保护和进程模块化的存储管理需求。例如,80x86体系CPU实现的段寻址技术,操作系统将在动态载入进程时的基地址配置入CPU的基地址寄存器(base register),CPU通过基地址寄存器和相对地址来产生物理地址。CPU提供的边界寄存器(bounds register)用来实现对进程的越界保护,当产生的物理地址越出指定范围,CPU产生一中断事件给操作系统处理。
为了实现进程在主存可以重定位,程序内的地址必须是逻辑的,而不能是物理的。实现逻辑地址(logical address)的一种方案是使用相对地址(relative address),相对于某已知的基地址。进程的[物理地址]由加载时获得的[基地址]加上程序编译链时接得到的[相对地址]算得。
进程重定位功能必须得操作系统的软件支持和CPU的硬件支持才能实现。
页式虚存管理机
实存管理技术(无论是静态还是动态的)对主存的利用率不高,原因是分配的粒度过大。试想如果能分配粒度更小主存框,主存的利用率一定能得到改善。但这种管理方案的基础和前提是实现分割进程的技术。这就是目前被普遍实现的[分页技术]。分页技术的思想是将进程分割为大小相等的页,主存分割为同样大小的页框,操作系统和CPU负责管理管理实现页与页框的映射关系。分页技术使用更小的主存框,降低了内部碎片的浪费;另外,分页技术支持不连续分配页框,也降低了外部碎片的浪费。
为了实现分页技术的[进程分割]和[不连续分配页框],程序的[逻辑地址]使用单一的[基地址寄存器加相对地址]进行一次转换的是不够的,操作系统必须为每一支进程创建一张页表(page table)对程序的[逻辑地址]作二次转换。操作系统将可用主存分割为同样大小页框,进程的页表保存着它所占用的页框的页框号。而页表的索引就是进程分割的页号(由0开始)。例如某进程P被分为五页,分别载入员框号为4,5, 6, 11,和 12的页框内,如下图。
程序内的[相对地址]在分页管理中进一步分为两部分:页号和页内偏移。进程的物理地址通过用页号查得页框号,再由页框号和页内偏移合并得到。
例如,假设系统使用16位地址,页大小为1K。那么一支2700字节大小的进程占用三页,如下图。当程序有相对地址的1502,那么如何算进程对应的物理地址呢?
1502的二进制是0000010111011110,由于页大小为1K,所以低10位用作页内偏移,高6位用作页号。那么相对地址1502位于1号页 (000001)内的478 (0111011110) 处。如果程序载入时1号页被分配到6号页框(000110),那相对地址的1502的对应的物理地址是0001100111011110,如下图。
分页技术最巧妙的地方是,当页大小为2的乘幂(2^n)时,页号和页内偏移对程序员、编译程序和链接程序是透明的。另外,地址转换过程只是将高位页号替换为页框号,硬件可非常容易并且高效实现。
一些处理器使用两级页表,像Pentium processor。在这种设计里,[顶级页表]称为页目录(page directory),一条目录项指向一张二级页表;这样如果页目录长度为X,页表最大长度为Y,那么每支进程可占用 X * Y 页。另外,页表最大长度取决于页大小,例如页大小为4Kib,那么如果页项为4byte,页表最大长度为1024。
下图(上部)展示了典型的使用二级页表划分32位地址空间的例子。假设我们是按字节寻址,页大小为4Kib,那么4-Gib (2^32) 虚拟地址空间由2^20页组成。如果页项(page table entry or PTE)大小为4byte,那么页表占用 4 Mib (2^22)的主存空间。这张庞大的页表(称为尾页表)本身就可被另一张页表(称为根页表)使用2^10页进一步映入虚存中。
上图(下部)展示了使用两级页表进行地址转换步骤。其中,进程的根页表是始终保存在主存上的,并由CPU根页表指针指向(具体如X86的cr3寄存器);虚拟地址前10位是一级页号,用以索引根页表,查得保存尾页表的页框(的基地址)。如果该页不在主存中,产生缺页事件;如果在,虚拟地址接着的10位用作二级页号,用以索引尾页表,查得最终的页框(的基地址),最后将页框的基地址和12位的偏移地址合并得到物理地址。
--todo-
(3)分级页表
一个32位逻辑地址空间的计算机系统,页大小为4KB,那么页表有一百万条目。假设每个条目占4B,则需要4MB物理地址空间来存储页表本身。利用多级页表,可以减少页表所占用的空间。
一个逻辑地址(32位系统,页大小 4K) 可以被分为 :一个20位的页号 +一个12位的偏移。如果对页表进行再分页,那么页号分解为:一个10位的页号 +一个10位的偏移。因此,一个逻辑地址表示如下 :p1 是用来访问外部页表的索引, p2 是外部页表的页偏移。
此时,两级32位分页结构的地址转换机制如下:
快表
在分页存储管理中,处理机每次存取指令或数据至少需要访问两次物理内存,即第一次访问页表,第二次存取指令或数据。为了提高地址变换速度,为进程页表设置一个专用的高冲存储器,称为“快表”、TLB,或联想存储器。用来保存当前访问频率高的少数活动页的页号及相关信息。
两级页表机制
将页表进行分页,每个页面的大小与内存物理块的大小相同,并为它们编号,可以离散地将各个页面分别存放在不同的物理块中,为此需要建立一张页表,称为外层页表,即第一级页表,其中每个表目是存放某个页表的物理地址。第二级是页表,其中的每个表目所存放的是页的物理块号。
----
段式虚存管理机
分页管理很像分任务管理中的静态分配,如分配固定大小主存框,产生内部碎片;只是分配的主存框更小,并且可以不连续。分段管理则很像分任务管理中的动态分配,如分配不定大小主存框,产生外部碎片;同时,分段管理又像分页管理,分割进程为多段,分配的主存框可以不连续。分段管理设计的哲学是将程序按逻辑结构分割,而不像分页管理的平均分割。按逻辑结构分割优点是储存管理不完全对程序员透明,程序员可手动优化储存管理;另外,按逻辑结构分割可实现代码共享,例如同一支程序的不同进程实例可共享同一个代码段。
分段管理不像分页管理那样普遍用来实现虚拟储存管理,因为很多RICS体系不支持分段管理,这里不细究分段管理与分页的具体差别。
存储管理与虚拟存储
物理内存资源管理与进程虚实地址转换是内核不同的任务。
当一支新进程被载入运行时,prc loader 向 mmgr申请物理内存页,然后将申请到的内存页构建进程的页表,这张页表用于进程虚实地址转换。
参考
http://www.xcbeyond.com/?p=551
第三章 存储管理(《操作系统》笔记整理)
http://lwn.net/Articles/250967/
《What every programmer should know about memory》
[存储管理机]的管理效率关系到整个多任务系统的性能。例如,如果系统主存只能装少量几个应用程序,而当主存中全是需频繁读写慢速IO设备的应用程序时,CPU频繁被闲置的同时,可能有其它就绪的应用程序因为没有被装入主存而被闲置,CPU资源没有被得到高效利用。
存储管理需求
无论计划设计或正在设计一项产品,我们务必时刻紧记产品所满足的需求(requirements),根据需求来考虑更好的设计策略。现代多任务计算机系统应用对操作系统的[存储管理机]设计提出以下一些需求:
- 进程移动(Relocation)
- 进程隔离保护(Protection)
- 数据共享(Sharing)
- 进程模块化(Logical organization)
- 虚拟存储
进程移动
在多任务计算机里,多个进程共享系统可用的主存。通常情况下,程序员在开发程序的时候不可能对程序实际运行在主存时的情况作任何假设,例如程序被具体装入到主存哪里,主存其它位置有什么进程等;
另外,为了最大化CPU的利用率,系统需要利用辅存(主要是磁盘)开辟一块的进程池(pool of ready processes),将阻塞的进程调出主存,将就绪的进程调入主存。当进程被调出主存后,我们很难知道它何时被再次调入,因为它必须被调入回原来的主存位置。然而这种静态置换是低效的。
综合以上两个需求,我们需要某种移动进程(或者叫重定位relocation)的技术,可以将进程移动到主存任意位置。这让我的关注点转移到进程对象运行时的存储结构上来,如下图:
此图展示了一支进程的存储结构。为了简化描述,我们假设进程被装入一块连续的主存区。由存储结构可知,操作系统必须知道
进程地址有,
- 第一,进程控制块的地址;
- 第二,进程调用栈的地址;
- 第三,进程的程序入口地址。
进程除了以上的结构性地址,程序内部的指令序列还有很多内存引用地址。例如,分支指令(语句)包含了下一条指令的地址;数据引用指令包含了数据字节(或字)的地址。
由上可推得,为了满足进程地址重定位的最直观方案就是,以进程为单位移动,进程内统一使用某种逻辑地址(例如相对地址),逻辑地址在执行时再由CPU硬件和操作系统转为物理地址。
虚拟存储
以进程为单位移动和管理存储,所得效率还是有限的。如果能将移动的单位深入到进程内部,将不常用的部分暂时移出主存,存储管理效率将会更高。这就向存储管理提出更高级的管理需求——进程内部存储管理。
在多任务技术发展的初期,程序员们曾经开发一种【前内存管理系统】——覆盖系统(overlay system)来实现内部存储管理的问题。因为那个时候操作系统还没有出现,程序员通过显式编码来实现overlay system。程序员把程序划分为不同的段(sections),每个段都会被整个载入主存执行一段时间。随着程序的运行推进,新的程序段会被载入,替换已经不需要的程序段。
内部存储管理的任务原是程序开发者的职责,但出于以下两个原因,管理任务还是收归给系统:
第一,开发者对程序的行为是了解的,但是存储管理毕竟不是解题相关的任务,由开发者实现存储管理,第一,分裂的开发者的角色,第二,增加了开发者的劳动;
第二,某些程序动态性过强,开发者不容易预测。
现代计算机系统统统实现了虚拟存储技术来满足进程内部存储管理需求。虚拟存储技术的核心是[虚拟存储器]的概念。虚拟存储器不是主存,也不是外存,而是操作系统和CPU利用二者实现的抽象的存储器,它的功能与主存一样,但是比主存要慢。虚拟存储技术假想将进程载入虚拟存器上运行,主存是虚拟存器的缓存,进程的常用代码和数据缓存在主存上。
要为进程虚构一个虚拟存储器,并且以主存为缓存,那么存储管理机必须负责管理缓存的[命中]和[不命中]处理,前者就是分页技术中用页表来实现虚实地址转换,后者就是分页技术中缺页处理。
As we discussed in Section 1.5, computer memory is organized into at least two lev-
els, referred to as main memory and secondary memory. Main memory provides fast
access at relatively high cost. In addition, main memory is volatile; that is, it does not
provide permanent storage. Secondary memory is slower and cheaper than main
memory and is usually not volatile. Thus secondary memory of large capacity can be
provided for long-term storage of programs and data, while a smaller main memory
holds programs and data currently in use.
In this two-level scheme, the organization of the flow of information between
main and secondary memory is a major system concern. The responsibility for this
flow could be assigned to the individual programmer, but this is impractical and un-
desirable for two reasons:
1. The main memory available for a program plus its data may be insufficient. In
that case, the programmer must engage in a practice known as overlaying, in
which the program and data are organized in such a way that various modules
can be assigned the same region of memory, with a main program responsible
for switching the modules in and out as needed. Even with the aid of compiler
tools, overlay programming wastes programmer time.
2. In a multiprogramming environment, the programmer does not know at the
time of coding how much space will be available or where that space will be.
It is clear, then, that the task of moving information between the two levels
of memory should be a system responsibility. This task is the essence of memory
management.
els, referred to as main memory and secondary memory. Main memory provides fast
access at relatively high cost. In addition, main memory is volatile; that is, it does not
provide permanent storage. Secondary memory is slower and cheaper than main
memory and is usually not volatile. Thus secondary memory of large capacity can be
provided for long-term storage of programs and data, while a smaller main memory
holds programs and data currently in use.
In this two-level scheme, the organization of the flow of information between
main and secondary memory is a major system concern. The responsibility for this
flow could be assigned to the individual programmer, but this is impractical and un-
desirable for two reasons:
1. The main memory available for a program plus its data may be insufficient. In
that case, the programmer must engage in a practice known as overlaying, in
which the program and data are organized in such a way that various modules
can be assigned the same region of memory, with a main program responsible
for switching the modules in and out as needed. Even with the aid of compiler
tools, overlay programming wastes programmer time.
2. In a multiprogramming environment, the programmer does not know at the
time of coding how much space will be available or where that space will be.
It is clear, then, that the task of moving information between the two levels
of memory should be a system responsibility. This task is the essence of memory
management.
进程隔离保护
在多任务的环境,每支进程都必须彼此隔离独立。为了避免进程间产生有意或无意相互干扰——某一进程在没有得到允许的情况下读写其它进程所分配的主存空间,操作系统有责任窃查进程行为。由于进程行为都表现对主存的访问,因此进程行为的检查归为存储管理,而不是进程管理。
从某种意义上说,[进程移动]与[进程保护]是对立的,进程重定位实现增加了进程保护的难度。由于[进程重定位],进程在主存中的位置变得不可预知,不可能在编译时检查绝对地址来实现保护。此外,很多高级语言支持在运行时动态计算来获得数据对象的地址,例如,C语言。
进程保护的可行办法是对进程运行时产生的所有地址进行检查,确保它们只访问属于自己的地址空间。可是,操作系统无法对进程的主存引用操作作全面的检查,光有操作系统(软件)是不够的,储存管理要实现[进程保护],必须得到CPU(硬件)支持。
幸运的是,现代处理器实现了强大的地址硬件,[进程移动]与[进程保护]同时得到实现。
数据共享
如果进程的隔离保护设计足够灵活,那么进程保护可以现实满足更高级的存储管理需求——数据共享。在多任务的环境下,多个进程共享数据的例子有:
第一,同一程序的多个进程实例可共享一份只读的代码;
第二,两支协作进程可共享一份数据来实现通信协作;
第三,基于同一个代码库,如标准C库,编写的多个进程可共享一份库代码,大大节省存储空间。
Any protection mechanism must have the flexibility to allow several processes to
access the same portion of main memory. For example,
if a number of processes are
executing the same program, it is advantageous to allow each process to access the
same copy of the program rather than have its own separate copy.
Processes that are cooperating on some task may need to share access to the same data structure.
The memory management system must therefore allow controlled access to shared
areas of memory without compromising essential protection. Again, we will see that
the mechanisms used to support relocation support sharing capabilities.
进程模块化
Almost invariably, main memory in a computer system is organized as a linear, orone-dimensional, address space, consisting of a sequence of bytes or words. Sec-
ondary memory, at its physical level, is similarly organized.
无论从概念上还是物理实现上,计算机主存都是线性的,无结构的。但是程序是有一定结构的,如一般程序有只读的代码段和可读写的数据段;进程运行时有一部分代码是常用的,有些则很少使用等。如果存储管理能以程序模块为位进行管理,而不整个程序,那么以下的一些需求将得到满足:
第一,程序模块可是单独编写和编译,并且可以在运行时动态链接和加载;
第二,进程保护可以以模块为单位;
第三,进程共享可以以模块为单位。
While this organization
closely mirrors the actual machine hardware, it does not correspond to the way in
which programs are typically constructed. Most programs are organized into modules, some of which are unmodifiable (read only, execute only) and some of which contain data that may be modified.
If the operating system and computer hardware
can effectively deal with user programs and data in the form of modules of some
sort, then a number of advantages can be realized:
1. Modules can be written and compiled independently, with all references from
one module to another resolved by the system at run time.
2. With modest additional overhead, different degrees of protection (read only,
execute only) can be given to different modules.
3. It is possible to introduce mechanisms by which modules can be shared among
processes. The advantage of providing sharing on a module level is that this
corresponds to the user’s way of viewing the problem, and hence it is easy for
the user to specify the sharing that is desired.
The tool that most readily satisfies these requirements is segmentation, which is one
of the memory management techniques explored in this chapter.
b.创新不是一个跳跃式灵动的结果,创作过程是对既有的经验的思维操作,最常见的操作是对比操作。由此可得,技术化创新(半自动化创新)的一种方法是让对比思维更方便。
b.如果创新是对已有经验和新经验类比出新idea,那么技术化创新的另一些方法包括,第一,丰富已有经验,让类比更有可能性;第二,掌握对已有经验有清晰科学的分类能力。
存储管理机管理设计
主存框
存储管理机管理的[资源]是主存,存储管理设计的第一任务是划分主存作管理的单位(memory allocation unit),这里统称其为主存框(memory frame);其次就是管理操作——为装入主存运行的进程分配主存区的分配算法。划分主存的方式决定了存储管理机的类型,各种类型的优点与缺点都不同,适用于不的计算机应用系统。固定实存分配不适于通用PC,但非常适合用于嵌入式单机系统,因为它调度算法简单高效。
分配算法
将进程装入主存,装入分两种情况,第一,当主存有剩余[主存框]时,选择合适的[主存框]直接装入(Placement);第二,当主存没有剩余[主存框]时,必须先解决将哪个[主存框]调出主存,再装入(Replacement)。现今大部分的现代多任务操作系统实现了非常复杂的虚拟储存技术。虚拟储存技术的实现基于如下两种技术中一种或两种:分段技术和分页技术。要掌握复杂的虚拟储存技术,我必须从零开始,了解储存管理技术发展历史。
存储管理机分类
根据实现[进程移动]时的地址翻译的难度,存储管理机分为[一次翻译的实存管理]和[二次翻译的虚存管理]两大类。在大类内又可根据[主存框]的类型进一步细分。
根据进程分配粒度,实存管理分为静态和动态实存; 静态实存管理按进程为单位进行分配和调度,并且主存框的划分是固定的(起始地址固定);根据主存框的[大小是否相等],静态实存管理机有[固定块式实存管理机]和[不定块实存管理机]两个变种。
动态实存主要有页式实存管理机和段式实存管理机两类。页框是大小固定的,段框则大小不一。
实存管理现在已经很少使用,由于它的实现比较原始,更好展示存储管理原理,对理解虚存管理有帮助;
虚存管理为了实现更灵活的存储管理,需要二次地址翻译——一张中间数据表提供翻译信息,例如页表。虚存管理设计的[主存框]类型主要有页和段,相应的存储管理机分别称为[页式虚存管理机]和[段式虚存管理机]。
实存管理机
1.静态实存管理机
1.1固定块式实存管理机
1.2不定块式实存管理机
2.动态实存管理机
2.1页式实存管理机
2.2段式实存管理机
虚存管理机
1.页式虚存管理机
2.段式虚存管理机
实存管理机
[固定块式实存管理机]优点是,第一,因为[主存框]大小和位置都是固定的,所以Placement算法很简单;第二,主存容纳进程的数量是固定的,Replacement算法也比较简单;缺点是,如果进程太大(超过[主存框]大小)则必须手动管理——主程序中有部分代码用来管理内存(如将部分代码或者调入调出),增加USER开发者劳动;如果太小,产生[内部碎片]——主存框没有装满,但也不能再被利用;[固定块式实存管理机]缓解(但不能解决)这两个不足。
[动态实存管理机]很好的解决了手动管理和内部碎片,但会产生[外部碎片]——主存没有装满,但剩余空间因不足再装一个新进程而不能再被利用。外部碎片必须重新回收——移动主存上的进程来合并碎片——才能再用,直接的结果,第一,增加系统开销;第二,增加开发技术难度(增加OS开发者劳动),因为进程必须能重定位才能移动。
由于[动态实存管理机]的[主存框]大小是不固定的,Placement算法相对复杂,因为如果有多块可用的[主存框]时,必须先决定装入哪块[主存框],常用的选择算法有Best-fit 、First-fit 和Next-fit。
实存管理机基本实现了进程移动、进程保护和进程模块化的存储管理需求。例如,80x86体系CPU实现的段寻址技术,操作系统将在动态载入进程时的基地址配置入CPU的基地址寄存器(base register),CPU通过基地址寄存器和相对地址来产生物理地址。CPU提供的边界寄存器(bounds register)用来实现对进程的越界保护,当产生的物理地址越出指定范围,CPU产生一中断事件给操作系统处理。
为了实现进程在主存可以重定位,程序内的地址必须是逻辑的,而不能是物理的。实现逻辑地址(logical address)的一种方案是使用相对地址(relative address),相对于某已知的基地址。进程的[物理地址]由加载时获得的[基地址]加上程序编译链时接得到的[相对地址]算得。
进程重定位功能必须得操作系统的软件支持和CPU的硬件支持才能实现。
页式虚存管理机
实存管理技术(无论是静态还是动态的)对主存的利用率不高,原因是分配的粒度过大。试想如果能分配粒度更小主存框,主存的利用率一定能得到改善。但这种管理方案的基础和前提是实现分割进程的技术。这就是目前被普遍实现的[分页技术]。分页技术的思想是将进程分割为大小相等的页,主存分割为同样大小的页框,操作系统和CPU负责管理管理实现页与页框的映射关系。分页技术使用更小的主存框,降低了内部碎片的浪费;另外,分页技术支持不连续分配页框,也降低了外部碎片的浪费。
为了实现分页技术的[进程分割]和[不连续分配页框],程序的[逻辑地址]使用单一的[基地址寄存器加相对地址]进行一次转换的是不够的,操作系统必须为每一支进程创建一张页表(page table)对程序的[逻辑地址]作二次转换。操作系统将可用主存分割为同样大小页框,进程的页表保存着它所占用的页框的页框号。而页表的索引就是进程分割的页号(由0开始)。例如某进程P被分为五页,分别载入员框号为4,5, 6, 11,和 12的页框内,如下图。
程序内的[相对地址]在分页管理中进一步分为两部分:页号和页内偏移。进程的物理地址通过用页号查得页框号,再由页框号和页内偏移合并得到。
例如,假设系统使用16位地址,页大小为1K。那么一支2700字节大小的进程占用三页,如下图。当程序有相对地址的1502,那么如何算进程对应的物理地址呢?
1502的二进制是0000010111011110,由于页大小为1K,所以低10位用作页内偏移,高6位用作页号。那么相对地址1502位于1号页 (000001)内的478 (0111011110) 处。如果程序载入时1号页被分配到6号页框(000110),那相对地址的1502的对应的物理地址是0001100111011110,如下图。
分页技术最巧妙的地方是,当页大小为2的乘幂(2^n)时,页号和页内偏移对程序员、编译程序和链接程序是透明的。另外,地址转换过程只是将高位页号替换为页框号,硬件可非常容易并且高效实现。
多级页表
原理上,一支进程对应一张页表,但当某支进程所使用的虚地址范围很大的时候,它的页表将大得难以接受。例如,在VAX architecture的系统里,每支进程占用 2^31 = 2 Gib的虚地址范围,按每页2^9 = 512-byte大小算,页表项高达2^22 条。为了解决这个问题,大多数虚存管理使用虚存本身——多级页表——来保存页表,而不是使用物理内存。当然[顶级页表]必须使用物理内存。使用虚存来保存页表意味着进程的部分页表可以不在物理内存上。一些处理器使用两级页表,像Pentium processor。在这种设计里,[顶级页表]称为页目录(page directory),一条目录项指向一张二级页表;这样如果页目录长度为X,页表最大长度为Y,那么每支进程可占用 X * Y 页。另外,页表最大长度取决于页大小,例如页大小为4Kib,那么如果页项为4byte,页表最大长度为1024。
下图(上部)展示了典型的使用二级页表划分32位地址空间的例子。假设我们是按字节寻址,页大小为4Kib,那么4-Gib (2^32) 虚拟地址空间由2^20页组成。如果页项(page table entry or PTE)大小为4byte,那么页表占用 4 Mib (2^22)的主存空间。这张庞大的页表(称为尾页表)本身就可被另一张页表(称为根页表)使用2^10页进一步映入虚存中。
上图(下部)展示了使用两级页表进行地址转换步骤。其中,进程的根页表是始终保存在主存上的,并由CPU根页表指针指向(具体如X86的cr3寄存器);虚拟地址前10位是一级页号,用以索引根页表,查得保存尾页表的页框(的基地址)。如果该页不在主存中,产生缺页事件;如果在,虚拟地址接着的10位用作二级页号,用以索引尾页表,查得最终的页框(的基地址),最后将页框的基地址和12位的偏移地址合并得到物理地址。
--todo-
(3)分级页表
一个32位逻辑地址空间的计算机系统,页大小为4KB,那么页表有一百万条目。假设每个条目占4B,则需要4MB物理地址空间来存储页表本身。利用多级页表,可以减少页表所占用的空间。
一个逻辑地址(32位系统,页大小 4K) 可以被分为 :一个20位的页号 +一个12位的偏移。如果对页表进行再分页,那么页号分解为:一个10位的页号 +一个10位的偏移。因此,一个逻辑地址表示如下 :p1 是用来访问外部页表的索引, p2 是外部页表的页偏移。
此时,两级32位分页结构的地址转换机制如下:
快表
在分页存储管理中,处理机每次存取指令或数据至少需要访问两次物理内存,即第一次访问页表,第二次存取指令或数据。为了提高地址变换速度,为进程页表设置一个专用的高冲存储器,称为“快表”、TLB,或联想存储器。用来保存当前访问频率高的少数活动页的页号及相关信息。
两级页表机制
将页表进行分页,每个页面的大小与内存物理块的大小相同,并为它们编号,可以离散地将各个页面分别存放在不同的物理块中,为此需要建立一张页表,称为外层页表,即第一级页表,其中每个表目是存放某个页表的物理地址。第二级是页表,其中的每个表目所存放的是页的物理块号。
----
段式虚存管理机
分页管理很像分任务管理中的静态分配,如分配固定大小主存框,产生内部碎片;只是分配的主存框更小,并且可以不连续。分段管理则很像分任务管理中的动态分配,如分配不定大小主存框,产生外部碎片;同时,分段管理又像分页管理,分割进程为多段,分配的主存框可以不连续。分段管理设计的哲学是将程序按逻辑结构分割,而不像分页管理的平均分割。按逻辑结构分割优点是储存管理不完全对程序员透明,程序员可手动优化储存管理;另外,按逻辑结构分割可实现代码共享,例如同一支程序的不同进程实例可共享同一个代码段。
分段管理不像分页管理那样普遍用来实现虚拟储存管理,因为很多RICS体系不支持分段管理,这里不细究分段管理与分页的具体差别。
存储管理与虚拟存储
物理内存资源管理与进程虚实地址转换是内核不同的任务。
当一支新进程被载入运行时,prc loader 向 mmgr申请物理内存页,然后将申请到的内存页构建进程的页表,这张页表用于进程虚实地址转换。
参考
http://www.xcbeyond.com/?p=551
第三章 存储管理(《操作系统》笔记整理)
http://lwn.net/Articles/250967/
《What every programmer should know about memory》