操作系统的内存是整个计算机缓存计算体系的关键部分。CPU是指令操作和计算的核心,但是CPU只相当于机械臂,相应的程序的指令集合和数据段等信息必须加载到内存中,类似于送上流水线,等待CPU读写执行更新,从而完成计算任务。内存相比于硬盘读写速度更快(100倍),当价格也更高(8G内存条在博客编写时价格在800rmb,2t引动硬盘大概在600rmb,比较可知,1G内存空间是1G硬盘空间价格的300倍左右),形象的类比,硬盘空间相当于工厂的仓库,而内存则相当于工厂的流水线,CPU相当于数控机床,显然程序的指令集合和数据段等信息只有当该程序被执行时才会被送上流水线这一比仓库更宝贵的资源。考虑到现今主流操作系统都是支持分时多用户场景的,如何高效地设置内存这一流水线的使用方式显然是提高工作效率的关键。
1.内存管理的意义
操作系统为了方便程序员开发程序,让应用层程序开发人员无需考虑太多底层的细节,故而将内存管理方式进行封装(封装内容包括页映射机制、基于局部性原理的页缓冲机制、页缺失中断和页调度机制、交换空间swap cache等内核机制),提出了“虚拟内存“概念,这一抽象概念(分时操作系统以”分时轮转“为设计原则设计操作系统的各部件,虚拟内存是这一思想的自然产物之一,是配合CPU scheduling的重要辅助设计)使得对于任一处于进程中的程序而言,仿佛是在独占使用内存一样,使得程序设计者摆脱了直接组装代码和物理内存单元的噩梦(基本上意味着汇编不离手了)。从而谈内存管理,必须分为两方面,对上,对CPU和程序要谈”虚拟内存空间“即logical address,对下,针对操作内核和MMU则是”页映射“等内核机制辅助的”物理内存空间“,即physical address。
2.分页管理
程序指令集合.code和数据段.data在内存中的存储方式(内存管理的最直观意义)直接决定了索引速度和空间利用率,甚至硬件系统需要提供特定的硬件支持。最早的内存管理方式侧重内存空间管理便捷性,产生了如下演化顺序:
固定分区(内存空间成片按顺序连续分配,易出现内部碎片,内部使用率低)—-> 动态重强调内容定位分区(取消顺序分配,跳转匹配适合,提升空间使用率,但需要配备额外的索引记录,每一次内存分配的粒度不一,记账复杂)—-> 分页式管理(将内存划分成以“页”为最小单位,进行批发供给,解决内存分配粒度不一导致的记账复杂,这种设定最小管理粒度的思想是极为有效的软件思想,如磁盘块、时间片等,将复杂的内存管理直观地简化成空间利用率和记账复杂度的平衡问题,给了设计者清晰的调节方向,即控制“页”大小即可)
从上面的演化进程,可以看到分页管理的核心思想:将物理内存划分成固定尺寸的blocks(称为frames帧),将逻辑内存划分成相同尺寸的blocks(称为pages页)。进程执行时,所需的page会被从磁盘等文件系统提取装载入空闲的物理内存frames(显然可以推理出磁盘空间为和方便和内存管理对接,同样会采用最小管理粒度的设计思想,磁盘块的大小是页帧的整数倍)。
程序设计者的角度看代内存是一个整体的当前进程独占式空间,即虚拟内存空间,而实际上该用户进程分散在物理内存的各个角落。操作系统负责将逻辑地址转换成物理地址,现今电脑为了加速这一地址转换过程往往都提供相应的硬件加速支持。如PTBR(page-table base register)和快表TLB。
页表基地址寄存器PTBR(page-table base register)
从上述内容可以推理出,操作系统既然负责掌管虚拟地址页和物理地址帧之间的切换,那么显然操作系统需要掌控当前物理内存各帧的使用情况,即空闲或占用,如果被占用,是属于哪个进程ID,对应该进程的哪一页,这些信息都需要有专门的数据结构存储,该数据结构被称为帧表frame table(可用扩展型的Bitmap)。而从进程的角度,它需要掌握该进程各逻辑页page对应的物理frame关系,从而可以让操作系统进行相应的读取操作,记录该对应关系的数据结构被称为页表page table。考虑到在进程装载运行期间,该表显然需要多次查阅,那么将该表的起始地址记录在专用寄存器中,显然可以加速对该表的搜索速度,这专用寄存器便是PTBR。
快表TLB(translation look-aside buffer)
快表TLB从使用性质上可以归类于cache,考虑到如果进程过大,显然该进程对应的页表规模也很大,即便全部存入内存中,遍历搜索的速度是受内存传输速度限制的。根据局部性原理(任一时刻程序将要使用的数据或指令更可能在当前指令的附近范围),将进程页表最可能命中的部分段提前加入cache(比内存速度快10倍),这部分专门用于存储局部页表的cache结构便称为快表。
Fig.2 分页式管理及相应的硬件加速支持
3.分段管理
但是这些内存管理方式单纯从内存空间管理的角度考虑问题,并没有兼顾到程序的逻辑结构。
Q: What if the hardware could provide a memory mechanism that mapped the programmer’s view to the actual physical memory?
A:有的,这种机制便是段Segmentation。分段存储管理:把程序作业按照逻辑关系加以分离,划分成若干段,如指令段.code,数据段.data,堆和栈等,并按照这些段的特性来针对性的设计内存映射方式。
摘录教材的一个分段地址转换过程示意,系统为每个作业定义了一张段表,每个表项至少有4各数据项,即段号、段长、内存起始地址和存取权限。
Fig.3 分段式管理及相应加速硬件
4.分页和分段的区别
- 页是信息的物理单位(eg 400Bytes/per page),分页是为了实现离散分配,提高内存利用率,便于系统管理;而段是信息的逻辑单位(.code.data.bss.rel.data etc),每一段在逻辑上是相对完整的一组信息,如一个函数、一个过程或一个数组,分段是为了满足用户的需求;
- 页式管理的逻辑空间是一维的(寻址只需要逻辑偏移量),段式是二维的,需要提供段号和段内偏移量;
- 页式管理中物理块尺寸是固定的,段是有具有相对完整意义的信息,长度不一。
5.段页式管理
分页式管理是为了有效提高内存的利用率,但是容易造成信息段的外部碎片;分段式管理充分考虑程序的逻辑结构,有效地满足用户的需求,但是导致物理内存的管理尺度不一,导致管理难度较大。段页式管理则是综合两者有点,对上,程序的逻辑空间采用分段式管理,对下,物理内存块采用分页式管理。段页式管理是三维的:段号、段内页号、页内偏移量。
Fig.4 段页式管理及相应加速硬件
段页式管理方式中的地址转换过程步骤:
1.首先利用段号S,加上段表地址寄存器,寻找到该逻辑段的段页对照表page-table入口;
2.利用段内页号在该段对应的页表中找到该页对应物理帧frame地址;
3.根据页内偏移量加上物理帧frame提供的基址,找到目标符号的物理地址。
显然可以看到段页式管理需要访问三次内存,分别是段表、页表、目标符号定位,故而为了提高访问速度,当前计算机都提供了在地址转换机构中增设一级高速cache,和上同理。