内存管理的概念
内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件一直在飞速发展,内存容量也在不断增长,但是仍然不可能将所有用户进程和系统所需要的全部程序和数据放入主存中,所以操作系统必须将内存空间进行合理地划分和有效地动态分配。操作系统对内存的划分和动态分配,就是内存管理的概念。
有效的内存管理在多道程序设计中非常重要,不仅方便用户使用存储器、提高内存利用率,还可以通过虚拟技术从逻辑上扩充存储器。
内存管理的功能有:
内存空间的分配与回收:由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率。
地址转换:在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致,因此存储管理必须提供地址变换功能,把逻辑地址转换成相应的物理地址。
内存空间的扩充:利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存。
存储保护:保证各道作业在各自的存储空间内运行,.互不干扰。
在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。
swap介绍
在详细介绍swap之前,我们需要知道的是计算机对内存分为物理内存与虚拟内存(注意虚拟内存和虚拟地址空间的区别)。物理内存就是计算机的实际内存大小,由RAM芯片组成的。虚拟内存则是虚拟出来的、使用磁盘代替内存。虚拟内存的出现,让机器内存不够的情况得到部分解决。当程序运行起来由操作系统做具体虚拟内存到物理内存的替换和加载(相应的页与段的虚拟内存管理)。这里的虚拟内存即所谓的swap。
当用户提交程序,然后产生进程,在机器上运行。机器会判断当前物理内存是否还有空闲允许进程调入内存运行,如果有那么则直接调入内存进行运行;如果没有,那么会根据优先级选择一个进程挂起,把该进程交换到swap中等待,然后把新的进程调入到内存中运行。根据这种换入和换出,实现了内存的循环利用,让用户感觉不到内存的限制。从这也可以看出swap扮演了一个非常重要的角色,就是暂存被换出的进程。
内存与swap之间是按照内存页为单位来交换数据的,一般Linux中页的大小设置为4kb。而内存与磁盘则是按照块来交换数据的。
虚拟内存的背景(virtual memory)
内存管理算法都是基于一个基本要求:执行指令必须在物理内存中,满足这一要求的第一种方法是整个进程放在内存中。动态载入能帮助减轻这一限制,但是它需要程序员特别小心地做一些额外的工作。
指令必须都在物理内存内的这一限制,似乎是必须和合理的,但也是不幸的,因为这使得程序的大小被限制在物理内存的大小内。事实上,研究实际程序会发现,许多情况下并不需要将整个程序放到内存中。即使在需要完整程序的时候,也并不是同时需要所有的程序。
因此运行一个部分在内存中的程序不仅有利于系统,还有利于用户。
虚拟内存(virtual memory)将用户逻辑内存和物理内存分开。这在现有物理内存有限的情况下,为程序员提供了巨大的虚拟内存。
物理和虚拟寻址
计算机系统的主存被组织成一个有M个连续的字节大小的单元组成的数组。每字节都有一个唯一的物理地址(PA)。第一个字节的物理地址为0,接下来的字节地址为2,依次类推。给定这种简单的结构,CPU方位内存的最自然的方式就是使用物理地址。我们把这种方式称为物理寻址(physical addressing)。
早期的PC使用的是物理地址,而且诸如数字信号处理器、嵌入式微控制器以及Cray超级计算机这样的系统仍然还是继续使用这种寻址方式。然而现代的处理器使用的是一种称为虚拟寻址(virtual address)的寻址方式。
使用虚拟地址,CPU通过生成一个虚拟地址(Virtual Address,VA)来访问主存,这个虚拟地址在被送到内存之前先转换成适当的物理地址。将这个虚拟地址转换成物理地址的任务叫做地址翻译(address translation)。就像异常处理一样,地址翻译需要CPU硬件和操作系统的紧密合作。CPU芯片上叫做内存管理单元(MMU)的专有硬件,利用存放主存中的查询表来动态的翻译虚拟地址,该表的内容由操作系统来管理。
地址空间Address spaces
地址空间是一个非负整数的有序集合{0,1,2,.......}。如果地址空间中的整数是连续的,那么我们说它是一个线性的连续地址空间。在一个带有虚拟内存的系统中,CPU从一个由N个地址的地址空间中生成虚拟地址,这个地址空间称为虚拟地址空间(virtual address space)。一个地址空间的大小是由表示最大地址所需要的位数来描叙的。现代系统通常支持32位或者64位虚拟地址空间。
一个系统还有一个物理地址空间(physical address space),对应于系统中物理内存的M个字节。地址空间的概念是十分重要的,因为它清楚地区分了数据对象(字节)和它们地属性(地址)。一旦认识到了这种区别,那么我们就可以将其推广了,允许每个数据对象有多个独立地地址空间,其中每个地址都选自一个不同的地址空间。这就是虚拟内存的基本思想。主存中的每字节都有一个选自虚拟空间的虚拟地址和一个选自物理空间的物理地址。
虚拟内存作为缓存的工具
概念上而言,虚拟内存被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。每字节都有一个唯一的虚拟地址,作为到数组的索引。磁盘上数组的内容被缓存到主存中。和存储器层次结构中其他缓存一样,磁盘(较低层)上的数据被分割为块,这些块作为磁盘和主存之间的传输单元。VM系统通过将虚拟内存分割为称为虚拟页(Vitrual Page)的大小固定的块来处理这个问题。每个页面大小为P字节。类似的,物理内存页被分割为物理页(Physical page,PP),大小也为P字节(物理页面也被称为页帧 Page frame)。
在任何时刻,虚拟页面的集合都分为三个不相交的子集:
未分配:VM系统还未分配(或者创建)的页。未分配的块没有任何数据和它们相关联,因此也就不占用任何磁盘空间。
缓存的:当前已缓存在物理内存中的已分配页。
未缓存的:未缓存在物理内存中的已分配页。
Page fault 缺页
当换入进程时,调页程序推测在该进程再次换出之前使用到的哪些页,仅仅把需要的页调入内存。从而减少交换时间和所需的物理内存空间。
这种方案需要硬件支持区分哪些页在内存,哪些在磁盘。采用有效/无效位来表示。当页表中,一个条目的该位为有效时,表示该页合法且在内存中;反之,可能非法,也可能合法但不在内存中。
如果进程从不试图访问标记为无效的页,那么并没有什么影响,因此,如果推测正确且只调入所有真正需要的页,那么进程就可如同所有页都调入内存一样正常运行。
当进程试图访问这些尚未调入内存的页时,会引起页错误陷阱(page-fault trap)。这种情况的处理方式如下:
1)检查进程的内部页表(通常与PCB一起保存)。以确定该引用是的合法还是非法的地址访问。
2)如果非法,则终止进程;如果引用有效但是尚未调入页面,则现在进行调入。
3)找到一个空闲帧(如,从空闲帧表中选取一个)。
4)调度一个磁盘操作,以便将所需页调入刚分配的帧
5)磁盘读操作完成后,修改进程的内部表和页表,表示该页已在内存中。
6)重新开始因陷阱而中断的指令。
计算机存储体系简介
存储器是分层次的,离CPU越近的存储器,速度越快,每字节的成本越高,同时容量也因此越小。寄存器速度最快,离CPU最近,成本最高,所以个数容量有限,其次是高速缓存(缓存也是分级,有L1,L2等缓存),再次是主存(普通内存),再次是本地磁盘。
寄存器的速度最快,可以在一个时钟周期内访问,其次是高速缓存,可以在几个时钟周期内访问,普通内存可以在几十个或几百个时钟周期内访问。
存储器分级,利用的是局部性原理。我们可以以经典的阅读书籍为例。我在读的书,捧在手里(寄存器),我最近频繁阅读的书,放在书桌上(缓存),随时取来读。当然书桌上只能放有限几本书。我更多的书在书架上(内存)。如果书架上没有的书,就去图书馆(磁盘)。我要读的书如果手里没有,那么去书桌上找,如果书桌上没有,去书架上找,如果书架上没有去图书馆去找。可以对应寄存器没有,则从缓存中取,缓存中没有,则从内存中取到缓存,如果内存中没有,则先从磁盘读入内存,再读入缓存,再读入寄存器。
2.计算机缓存 Cache
本系列的文章重点介绍缓存cache。了解如何获取cache的参数,了解缓存的组织结构。
2.1 Cache 概述
cache,中译名高速缓冲存储器,其作用是为了更好的利用局部性原理,减少CPU访问主存的次数。简单地说,CPU正在访问的指令和数据,其可能会被以后多次访问到,或者是该指令和数据附近的内存区域,也可能会被多次访问。因此,第一次访问这一块区域时,将其复制到cache中,以后访问该区域的指令或者数据时,就不用再从主存中取出。