一般一个32位进程有2G的内存可以用,如果是只用到100多M就出现异常崩溃的话,首先要看下是报错的原因,是out of memory,还是access error。如果是后面一种情况的话,就是代码错误,比如访问了已经释放的内存,或者内存越界。
这里简要说明如下:
一、4GB地址空间的局限
首先我们还必须要先了解两个概念:
其一是“物理内存”。大家常说的物理内存就是指安装在主板上的内存条,其实不然,在计算机的系统中,物理内存不仅包括装在主板上的内存条(RAM),还应该包括主板BIOS芯片的ROM,显卡上的显存(RAM)和BIOS(ROM),以及各种PCI、PCI-E设备上的RAM和ROM。
其二是“地址空间”。地址空间就是对物理内存编码(地址编码)的范围。
所谓编码就是对每一个物理存储单元(一个字节)分配一个唯一的地址号码,这个过程又叫做“编址”或者“地址映射”。这个过程就好像在日常生活中我们给每家每户分配一个地址门牌号。与编码相对应的是“寻址”过程——分配一个地址号码给一个存储单元的目的是为了便于找到它,完成数据的读写,这就是“寻址”,因此地址空间有时候又被称作“寻址空间”。系统不仅要给主板上的内存条编址,还要给上述的其它物理内存编址;它们都被编在同一个地址空间内,编址后的物理内存就可以被系统资源使用或占用。
从Pentium Pro处理器开始,CPU的地址总线已经升级到36位,寻址能力达到64GB,按理说CPU支持4GB的内存是没有问题的;因此,芯片组(北桥—MCH)地址总线的数量就成了决定物理内存地址空间大小的决定性因素。在Intel 945系列和945以前的芯片组,nForce 550系列和550以前的芯片组都只有32条地址线,为系统提供4GB的地址空间,即最高可以安装4GB的内存条。
虽然可以安装4GB内存条,但这4GB的内存空间不能全部纷配给内存,因为从4GB空间的顶端地址(FFFF_FFFFh)开始向下要有400MB-1GB的地址空间要分配给主板上的其他物理内存。如下图:
从图中我们可以看到4GB的地址空间可以分为两大部分,0MB~物理内存顶端的地址分配给主板上安装的物理内存,4GB到物理内存顶端的地址分配给BIOS(ROM)和PCI/PCI-E设备的存储器。由于这些存储器基本上是用于系统的输入和输出,所以Intel又把这段地址空间称之为“MMIO”(Memory-Mapped I/O—I/O存储器映射)。当系统安装3GB以下的内存时,MMIO区域不会与物理内存条的地址空间相重叠,操作系统可以访问几乎全部的物理内存,而操作系统属性里显示的物理内存基本接近实际内存的容量。
而当系统安装上4GB内存时,问题出现了。由于位于4GB下面的部分地址空间要优先分配给MMIO,内存条上对应的这段区间就得不到编址,所以操作系统就不能使用。
严格意义上来说,即使安装2GB内存时操作系统也不可能使用到全部的内存容量,诸如传统DOS的UMA区就有部分被占用的地址空间,但因为被占用的容量相比之下实在太少,所以就被很多读者忽略了。MMIO占用的地址空间在256MB~1GB之间,这么大的“浪费”大家肯定不能“熟视无睹”。
因为受4GB芯片组地址空间的限制(32条地址线的限制),Intel 945系列及以前的芯片组、NVIDIA nForce 550及以前的芯片组都没有办法绕过这个限制。具体原因有三方面:其一是芯片组没有剩余空间分配来供操作系统来调配;其二是物理内存的编址必须是连续的,不能被割断;其三是系统开机时必需先从4GB的顶端地址(FFFF_FFFFh)读取BIOS数据, 这是IA32架构和4GB地址空间的局限.
所以建议使用这些芯片组主板的用户不要安装4GB的内存,这样会有部分内存容量不能被操作系统所使用。而解决4GB内存限制的唯一办法就是扩展地址空间。
二、支持大于4GB内存的芯片组和“内存重映射”技术
面对原有芯片组4GB内存的局限,Intel和NVIDIA早就开始未雨绸缪,他们对传统的32位地址总线进行了调整,将其升级到36位,并推出了一系列可以突破4GB内存限制的芯片组,这就是Intel的965系列以及975系列、NVIDIA的nForce 570/590以及680系列。
表2:支持4GB以上内存的芯片组
注:AMD的64位Socket AM2 CPU把内存控制器放到CPU中,提供40bit的物理地址总线,地址空间可达到1000GB。具体支持的地址空间和内存量取决于芯片组及主板的总线设计。
从上面的芯片组参数来看,地址总线从32位提升到36位,地址空间达到64GB,支持安装8GB的物理内存。但由于IA32架构的规则是开机时必须从4GB的FFFF_FFFFh地址读取BIOS信息,尽管芯片组支持的地址空间变大了,且最大支持的物理内存容量也达到了8GB(或以上),但从本质上来说仍然不能解决MMIO地址占用4GB内存编址的问题。这要怎么办呢?
36位地址总线最大可以支持64GB的地址空间,这就为移动MMIO地址区提供了条件。现在解决这个问题的办法就是“内存重映射”技术——就是在IA32架构的基础上,把BIOS(ROM)和PCI/PCI-E设备占用的MMIO地址区段重新映射到内存条顶端地址以上 (例如4GB以上)的地址空间,从而把IA32架构规定的这一段操作系统不可使用的、位于4GB下面的MMIO地址空间回收给物理内存使用,保证物理内存编址的连续性。具体的映射方式如下图所示。
三、BIOS必须支持“内存重映射”
“内存重映射”技术必须通过BIOS完成。所以BIOS必须具有支持内存重映射的功能模块,以便根据用户安装的内存容量来确定是否需要启用内存重映射功能。同时,在BIOS的设置选单中也要有“Memory Re-Mapping”的设置选项,使用4GB或者4GB以上内存的用户一定要将此项设置设为“Enable”,如下图所示:
四、解决4GB内存问题还需要操作系统支持
我们常使用的桌面操作系统是32位的,支持4GB的地址空间。前面我们介绍了解决4GB问题的芯片组是支持64GB地址空间的,在这样的芯片组主板上安装32位的操作系统,就只能使用4GB的地址空间,因此安装4GB内存不能使用仅支持4GB地址空间的32位的操作系统。应该使用支持大于4GB地址空间的32位操作系统或64位的操作系统。
五、小结
1、由于iA32架构要求BIOS(ROM)芯片的地址, PCI、PCI-E存储器地址、APCI中断路由地址等必须占用从4GB开始以下的256M-1GB空间。这段MMIO地址区不能分配给内存条。4GB的内存条有256MB-1GB的容量不能编址而浪费。
2、使用4GB以上的内存条,必须使用地址(编址)空间64GB的芯片组主板。
3、内存重映射就是把被MMIO占用的地址移到内存条容量以上的地址空间。
4、BIOS应具有支持“内存重映射”功能,设置项里有 Memory Remap Feature 选项,并设置为Enable。
5、必须安装寻址空间大于4GB的操作系统。比如Windows 2000高级服务器版,以及64位操作系统(表3)。
6、所有地址空间为4GB的芯片组(Intel945和nForce550之前的),和32位操作系统均不能利用“内存重映射”技术解决4GB 以下一篇文章较详细的说明了这个情况,大家可以得到很好的理解。
/****************************************************************
计算机按照运算速度的快慢分为了几层,最顶层为CPU,接着是L1、L2、L3等多级缓存,接着是内存,最后才是硬盘,它们的速度由快到慢。其中多级缓存、内存和硬盘都是作为存储设备使用的。
由于计算机采用多道程序设计,因此在内存中会同时存在多个进程,但是同一时间只会运行一个,当内存空间不足时,os会将内存中没有运行的进程移入到硬盘中,此时硬盘被称为虚拟内存。
地址类似于门牌号,内存是线性一维的,可以把它比作一维数组,它的下标从零开始依次递增,其中这个下标就被称作地址,CPU根据这个下标就可以获取到指定位置的内容。
逻辑地址空间是指所有内存空间都可以使用,它通过一个表格和mmu硬件映射到物理地址空间,程序中使用的都是逻辑地址空间,只有当经过重定向后才会将逻辑地址空间转为物理地址空间。
当要给一个程序分配内存时,有多种分配方式,假设现有程序A需要内存300k,内存空间中存在内存空闲块400k,500k,300k,根据算法的不同分配策略也不同:
第一种:最先分配,顾名思义,就是遍历整个空闲块,第一个适合的就选中,此例子中按这种算法会选中400k的空闲块
第二种:最优分配,遍历所有空闲块,找到大小最合适的,此例子中会选中300k的空闲块
第三种:最差分配,遍历所有空闲块,找到大小相差最大的,此例子中会选中500k的空闲块
无论是哪种算法,都有其优点和缺点,区别在于速度的快慢和产生碎片的大小。
经过了内存分配算法分配之后,随着时间的推移,会产生一些小的空闲块,但是这些小的空闲块单独并不能给任何应用提供空间,如果能把它们合并的话就可以重新为新的应用分配空间。合并小内存块的行为称为碎片整理,或者称为内存回收。
内存回收也分为多种方式,比如按照临近的两个空闲块合并,或者将所有应用都移到另一端等等,每种回收算法也有其各自的优缺点。
/********************************************************
为了更加有效地管理存储器且少出错,现代系统提供了一种对主存的抽象概念,叫做虚拟存储器(VM)。虚拟内存是硬件异常,硬件地址翻译,主存,磁盘文件和内核软件的完美交互。它为每个进程提供一个大的,一致的和私有的地址空间。它提供了3个重要能力。
逻辑地址(Logical Address):程序中指令所用地址(进程所在地址空间),也称为虚拟地址(Virtual Address,简称VA)
物理地址(Physical Address,简称PA):存放指令或数据的实际内存地址,也称为实地址、主存地址。物理地址(Physical Address,PA):计算机系统的主存被组织为M个连续的字节大小的单元组成的数组。每个字节的地址叫物理地址.
CPU访问存储器的最自然的方式使用物理地址,这种方式称为物理寻址。早期的PC,数字信号处理器,嵌入式微控制器以及Cray超级计算机使用物理寻址。
现代处理器使用的是虚拟寻址(virtual addressing)的寻址形式。CPU通过生成一个虚拟地址(Virtual address,VA)来访问主存。将虚拟地址转换为物理地址叫做地址翻译(address translation)。地址翻译需要CPU硬件和操作系统之间的紧密结合。CPU芯片上有叫做内存管理单元(Memory Management Unit,MMU)的专用硬件,利用存储在主存中的查询表来动态翻译虚拟地址,查询表由操作系统管理。
虚拟存储技术的引入用来解决一对矛盾
• 一方面,由于技术和成本等原因,主存容量受到限制
• 另一方面,系统程序和应用程序要求主存容量越来越大
虚拟存储技术的实质
• 程序员在比实际主存空间大得多的逻辑地址空间中编写程序
• 程序执行时,把当前需要的程序段和相应的数据块调入主存,其他暂不用的部分存放在磁盘上
• 指令执行时,通过硬件将逻辑地址(也称虚拟地址或虚地址)转化为物理地址(也称主存地址或实地址)
• 在发生程序或数据访问失效(缺页)时,由操作系统进行主存和磁盘之间的信息交换
虚拟存储器机制由硬件与操作系统共同协作实现,涉及到操作系统中的许多概念,如进程、进程的上下文切换、存储器分配、虚拟地址空间、缺页处理等。
地址空间(address space)是一个非负整数地址的有序集合。如果地址空间中整数是连续的,我们说它是线性地址空间(linear address space)。为了简化讨论,我们总是假设使用线性地址空间。在一个带虚拟存储器的系统中,CPU从一个有N=2^n个地址的地址空间中生成虚拟地址,这个地址空间称为虚拟地址空间(virtual address space)。一个地址空间大小是由表示最大地址所需要的位数来描述的。如N=2^n个地址的虚拟地址空间叫做n位地址空间。现在操作系统支持32位或64位。一个系统还有物理地址空间,它与系统中物理存储器的M=2^m(假设为2的幂)个字节相对应。
地址空间的概念很重要,因为它区分了数据对象(字节)和它们的属性(地址)。每个字节(数据对象)可以有多个 独立的地址(属性),每个地址都选自不同的地址空间。主存中的每个字节都有一个在虚拟地址空间的虚拟地址,还有一个在物理地址空间的 物理地址。
虚拟存储机制为程序提供了一个极大的虚拟地址空间也称为逻辑地址空间.它是主存和磁盘存储器的抽象。虛存机制带来了一个假象.使得每个进程好像都独占使用主存.并且主存空间极大。这有三个好处
①每个进程具有一致的虚拟地址空间.从而可以简化存储管理;
②它把主存看成是磁盘存储器的一个缓存,在主存中仅保存当的活动的程序段和数据区.并且根据需要在磁盘和主存之间进行信息交换,通过这种方式.使有限的主存空间得到了有效利用;
③每个进程的虚拟地址空间是私有的.因此,可以保护各自进程不被其他进程破坏。
分页基本思想:
• 内存被分成固定长且比较小的存储块(页框、实页、物理页)
• 每个进程也被划分成固定长的程序块(页、虚页、逻辑页)
• 程序块可装到存储器中可用的存储块中
• 无需用连续页框来存放一个进程
• 操作系统为每个进程生成一个页表
• 通过页表(page table)实现逻辑地址向物理地址转换(Address Mapping )
实现虚拟存储器管理,需考虑:
块大小(在虚拟存储器中“块”被称为“页 / Page”)应多大?
主存与辅存的空间如何分区管理?
程序块 / 存储块之间如何映像?
逻辑地址和物理地址如何转换,转换速度如何提高?
主存与辅存之间如何进行替换(与Cache所用策略相似)?
页表如何实现,页表项中要记录哪些信息?
如何加快访问页表的速度?
如果要找的内容不在主存,怎么办?
如何保护进程各自的存储区不被其他进程访问?
这些问题是由硬件和OS共同协调解决的!
有三种虚拟存储器实现方式:分页式、分段式、段页式
与“Cache--主存”层次相比:
页大小(2KB~64KB)比Cache中的Block大得多! Why?
采用全相联映射!Why?
因为缺页的开销比Cache缺失开销大的多!缺页时需要访问磁盘(约几百万个时钟周期),而cache缺失时,访问主存仅需几十到几百个时钟周期!因此,页命中率比cache命中率更重要!“大页面”和“全相联”可提高页命中率。
通过软件来处理“缺页”!Why?
缺页时需要访问磁盘(约几百万个时钟周期),慢!不能用硬件实现。
采用Write Back写策略! Why?
避免频繁的慢速磁盘访问操作。
地址转换用硬件实现!Why?
加快指令执行
每个进程有一个页表,其中有装入位、修改(Dirt)位、替换控制位、访问权限位、禁止缓存位、实页号。页表首址记录在页表基址寄存器中。页表就是一个页表条目(Page Table Entry,PTE)的数组.虚拟地址空间中每个页在页表的固定偏移量处都有一个PTE.每个PTE由一个有效位和n位地址字段。有效位表明虚拟页是否被缓存。如果有效位存在,那么地址字段指向对应的物理存储器。如果有效位不存在,地址字段要么为NULL,要么指向虚拟页在磁盘所在的位置。
问题:虚拟页与主存页框之间采用全相联方式进行映射,为何不像全相联Caceh那样(高位地址是Tag),而高位地址是索引呢?
上图中,VA:虚拟地址,PTEA:页表条目地址,PTE:页表条目,PA:物理地址
图(a)展示页面命中,CPU硬件执行过程
MMU
。MMU
生成PTE
地址(PTEA
),并从高速缓存/主存请求中得到它。PTE
。MMU
构造物理地址(PA),并把它传送给高速缓存/主存。页面命中完全由硬件处理,与之不同的是,处理缺页需要 硬件和操作系统内核协作完成。
PTE
有效位是零,所以MMU
触发异常,传递CPU中的控制到操作系统内核中的 缺页异常处理程序。PTE
。信息访问中可能出现的异常情况
1)缺页( page fault)
产生条件:当Valid(有效位 / 装入位)为 0 时
相应处理:从磁盘读到内存,若内存没有空间,则还要从内存选择一页替换到磁盘上,替换算法类似于Cache,采用回写法,淘汰时,根据“dirty”位确定是否要写磁盘当前指令执行被阻塞,当前进程被挂起,处理结束回到原指令继续执行
2)保护违例( protection_violation_fault )或访问违例
产生条件: 当Access Rights (存取权限)与所指定的具体操作不相符时
相应处理:在屏幕上显示“内存保护错”或“访问违例”信息,当前指令的执行被阻塞,当前进程被终止
Access Rights (存取权限)可能的取值有哪些? R = Read-only, R/W = read/write, X = execute only
利用TLB加速地址翻译
每次CPU产生一个虚拟地址,MMU
就必须查阅一个PTE
,以便将虚拟地址翻译为 物理地址。在最糟糕的情况下,会从内存中多取一次数据,代价是几十 到几百个周期 ,如果PTE
碰巧缓存在L1
中,那么开销就下降到一到两个周期。许多系统都试图消除这样的开销,他们在MMU
中包含了一个关于PTE
的小缓存,称为翻译后备缓冲器(Translation Lookaside Buffer,TLB),(
把经常要查的页表项放到Cache中,这种在Cache中的页表项组成的页表称为Translation Lookaside Buffer )。
TLB
是一个小的,虚拟寻址的缓存,一行都保存着一个由单个PTE
组成的块。
CPU访存时,地址中虚页号被分成tag+index,tag用于和TLB页表项中的tag比较,index用于定位需要比较的表项。
TLB全相联时,没有index,只有Tag,虚页号需与每个Tag比较;TLB组相联时,则虚页号高位为Tag,低位为index,用作组索引。
TLB采用全相联
TLB和cache的访问过程
TLB采用组相联
用于组选择和行匹配的索引和标记字段是从虚拟地址中的虚拟页号中提取出来的。如果TLB有T=2^t个组,那么TLB索引(TLBI)是由VPN的t个最低位组成,(对应于VPO)。TLB标记(TLBT)是由VPN中剩余位组成(对应于VPN)。
下图展示了当TLB
命中时的步骤,关键点:所有的地址翻译步骤都是在芯片上的MMU中执行的,因此非常快。
TLB
命中
MMU
从TLB
取出对应的PTE
。MMU
将这个虚拟地址翻译成一个物理地址,发送到高速缓存/主存
高速缓存/主存
所请求的数据字返回给CPUTLB
不命中的时候,MMU
必须从L1
缓存或内存中取出相应的PTE
,并进行类似缺页处理过程。/********************************************************************************
传统管理方式的特征、缺点
一次性:作业必须一次性全部装入内存后才能运行。
作业很大时,不能全部装入内存,导致大作业无法运行
大量作业运行时,由于内存无法容纳所有作业,因此只有少量作业能运行,导致多道程序并发度下降。
驻留性:一旦作业被装入内存们就会一直驻留在内存中明知道作业运行结束,事实上没在一个时间段,只需要访问作业的一小部分数据即可正常运行,这就导致了内存中会大量驻留暂时用不到的数据。
高速缓冲技术:
将近期会频繁访问到的数据放到发更高速的存储器中,暂时用不到的数据会放在更低速的存储器中。
快表机构就是将近期常访问的页表项副本放到更高速的联想寄存器中。
虚拟内存的定义和特征
基于局部性原理,在程序装入时,可以将程序中很快用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行
在程序执行过程中,当访问的信息不存在时 ,由操作系统负责将所需要的信息从外存调入内存,然后继续执行程序
若内存空间不够,由操作系统负责将内存中暂时不用的信息换到外存。
虚拟内存是操作系统虚拟性的一个体现,实际物理内存大小没有变,只是在逻辑上进行了扩充。
三个特征
多次性:无需再作业一次运行时一次性装入内存,而是允许被分成多次调入内存。
对换性:在作业运行时无需一直常驻,而是允许在作业运行中,将作业换入换出
虚拟性:从逻辑上扩充了内存的容量,远大于实际的容量
怎样实现
操作系统要提供请求调页(或请求段)功能
操作系统要提供页面置换或段置换功能
请求分页管理方式
页表机制
与基本分页管理相比,请求分页管理中,为了实现请求调页,操作系统需要知道每个页面是否已经调入内存;如果还没有,也要知道该页面在外存中存放的位置。
操作系统需要记录各个页面是否被修改的信息。
请求页表项增加了四个字段。
缺页中断机构
在请求分页系统中,每当要访问的页面不存在时,内存中便会产生一个缺页中断,然后由操作系统的缺页中断处理程序完成中断。
此时缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。
如果内存中有空闲块,将所缺页面装入该块,并修改页表中相应的页表项
如果内存中没有空闲块,则由页面置换算法选择一个页面淘汰,若该页面在内存期间被修改过,则要将其写回外存,未修改过的页面不用写回外存。
缺页中断是因为当前执行的指令要访问的目标页面未调入内存而产生的,因此属于内中断。
一条指令在执行期间,可能多次产生缺页。
地址变换机构
请求调页
页面置换
需要修改请求页表中新增的表项
页面置换算法
应该追求更少的缺页率。
最佳置换算法OPT
思想:每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。
前提条件:预先知道访问序列。
先进先出置换算法FIFO
思想:每次选择淘汰的页面时最早进入内存的页面。
实现:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面就可。
队列的最大长度取决于系统为进程分配了多少的内存块。
最近最久未使用置换算法LRU
思想:每次淘汰的页面时最近最久未使用的页面
实现:赋予每个页面对应的页表,用访问字段记录上次被访问以来所经历的时间t,当需要淘汰一个页面时,选择页面中t值最大的,即最久没有使用的页面。
需要专门的硬件支持,虽然算法性能好,但是实现困难,开销大。
时钟置换算法CLOCK
实现:为每个页面设置一个访问位置,再将内存中的页面都通过链接指针连接成一个循环队列。当某个页面被访问时,访问位置为1,当需要淘汰一个页面,只需检查页的访问位。若是0,将该页换出,若是1,将1换为0,不换出。继续下一个页面,若第一轮扫描都是1,将访问位置依次置0,进行第二轮扫描。
改进型时钟置换算法
除了考虑一个页面最近有没有被访问过外,还要考虑有没有被修改过,在其他条件相同时,应优先淘汰没有修改过的页面。
修改位=0,表示是页面没有修改,为1表示页面被修改过。
(1,1)表示一个页面近期被访问过。
页面分配策略
驻留集:指请求分页存储管理中给进程分配的物理块的集合。
固定分配:操作系统为每个进程分配了一组数目固定的物理块,在进程运行期间不再改变。
可变分配:先为进程分配一定数目的物理块,在程序运行期间,可以根据情况适当增加或者减少。
局部置换:发生缺页时只能选进程自己的物理块进行置换。
全局置换:可以将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页。
固定分配局部置换
可变分配全局置换
可变分配局部置换
调入页面
何时
预调页策略:根据局部性原理,一次调入若干相邻的页面可能比一次调入一个页面更加高效。但如果提前调入的页面中大多数都没有被访问过,则又是低效的。
请求调页策略:进程再运行期间发现缺页时才将所缺的页面调入内存。i/o开销比较大。
何处
系统有足够的对换区:页面的调入、调出都是再内存和对换区之间进行,这样可以保证页面的调入、调出速度很快。在进程运行前、需要将进程相关的数据从文件区复制到对换区。
系统缺少足够的对换空间:凡是不会被修改的数据都直接从文件区调入,由于这些页面不会被修改,因此换出时不必写回磁盘,下次需要时再从文件区调入,对于可能被修改的部分,换出时需写回磁盘对换区,下次需要时再从对换区调入。
UNIX方式:运行前进程相关数据全部在文件区,未使用的页面,都可从文件去调入,若是用过的页面要换出,则写回对换区,下次有需要时从对换区调入。
抖动(颠簸)现象
刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为称为抖动或颠簸。产生的原因是进程频繁访问的页面数目高于可用的物理块数(分配给进程的物理块不够)
工作集
驻留集:指请求分页存储管理中给进程分配的内存块的集合。
工作集:指在某段时间间隔里,进程实际访问页面的集合。