前言
500元、300元、150元......随着DDR2价格的逐渐崩盘,目前连2GB DDR2-800内存的价格也已经跌至百元,越来越多的朋友为爱机装上了4GB内存。随着4GB电脑的逐渐增加,一个长期存在的问题又再次被人们所关注:为何我只能看到3.25GB物理内存?
无论是WinXP-32bit还是Vista-32bit,所有的用户都可以发现自己的任务管理器中最多只显示3.25GB物理内存,更甚者还会有2.8GB甚至更低的数值出现。我们花钱购买的内存就这样白白不见了么?
人们当然不会允许这样的事情发生,于是各种论坛上展开了关于4GB内存的大量讨论。重装系统、打开PAE、使用Ramdisk、开启Memory Remapping等等各种手段层出不穷,所有人都想找回那失去的内存。再逐一尝试之后,人们发现始终能够在32bit系统上找到那0.75GB内存的下落。人们所寄希望的Vista系统也仅仅是能够在系统属性上看到4.00GB的字样,设备管理器的物理内存依然安逸的保持在3.25GB。期间,各大电脑网站和杂志也刊登了一些关于这方面的文章,介绍了大量内容,最终人们将一切归罪于32bit操作系统。
这样的审判似乎很正确,毕竟我们可以真实的看到64bit系统下那>3.25GB的物理内存显示,32bit系统显然贪污掉了0.75GB内存。然而事实上,操作系统却在这里成为了不折不扣的替罪羊。因为事实上即使是在64bit系统中,内存同样会被“侵蚀”。
为了让广大网友都能够了解事实究竟,今天笔者就为操作系统客串一次辩护律师,为其平反这个内存贪墨案,找寻那失落的内存。真相永远只有一个!
注:文本将以Intel当代芯片组的内存分配机制为例讲述,其他品牌芯片组在细节上或许有与本文所描述不同之处,但结论上不会有太大出入。
观念上的错误:32bit寻址
32bit操作系统,32bit处理器,有着32bit寻址能力,可以访问2^32 = 4G物理地址,于是拥有识别4GB内存的能力,这似乎是完全顺理成章的事情。然而其中有一个关键,什么是物理地址?物理地址就是物理内存的地址?非也。物理地址是指处理器和系统内存之间所用到地址,我们可以简单理解成是CPU“极方便访问的地址”。这个地址并非物理内存独享,而是被分成了很多部分,物理内存地址也只能够占用这4GB地址中的一部分。
认真看看上面这个P45芯片组的系统地址区域图。图中的方块代表的是不同区域的“地址”,这些地址囊括了一台电脑中所有能和操作系统以及芯片组关联的设备地址,而不仅仅是“物理内存地址”。同样的,那个4G的红线代表的是第4G个Byte的地址,并不是4GB物理内存的分界线。由于P45芯片组是一款支持36bit寻址的产品,即可以支持64GB地址,因此从左边的“系统视角”来看各种设备所需地址轻松自如的分布在整个地址表上。然而从右侧的“内存控制器视角”来看结果就不相同了。因为32bitCPU只能访问到4GB的地址,因此系统运转所必须的所有设备地址都必须同时存在于这4GB地址内。很显然,让一个系统正常运行并不仅仅包括内存,还要包括各种I/O设备等。在4GB的寻址范围内,物理内存实际上只占据了一块,那个被称为Main Memory Address Range的区域(图中绿色框)。那么其他地址主要被谁占据了呢?
上面的图中展示了00000000h至FFFFFFFFh共4GB地址的详细分配(上图中方块大小于占用地址多少无关),除去物理内存(Main Memory)之外,多数部分通常只会占据几MB最多十几MB的地址空间,其中唯一的一个地址大户是PCI Memory Address Range(PCI Memory Range)。
有一点我们必须再次明确,到目前为止我们都在讲“地址”,无论是4GB或者64GB,这里并不是在讲述任何与存储设备空间相关联的NAND gate或者磁颗粒数量(比如内存、硬盘空间),而是由16进制计数的物理地址。32bit寻址由CPU决定,因此即使你安装不到4GB的物理内存,系统仍然会拥有4GB的系统内存地址。上面的图很直观的说明了这一点,尽管只有2GB的物理内存,但系统依然分配出了00000000h至FFFFFFFFh共2^32bit = 4GB的地址。而且我们还可以发现从80000000h至FFFFFFFhF这整整2GB的地址都分配给了PCI bus,也就是前面所讲到的PCI Memory Address Range。
内存地址“侵蚀者”:PCI Memory Address Range
PCI Memory Address Range这一部分包含了各种I/O设备,系统总线等部分所需的地址,上面的图中我们可以看到ICH10的磁盘控制器、PCIE(显卡)等该系统现有设备所占据的地址范围。这些I/O设备地址被通过一种叫做MMIO的技术使得CPU可以高速便捷的访问它们。根据设备状况的不同,PCI Memory Address Range的大小也会发生变化,这都一切取决于硬件本身,例如芯片组、显卡等等。
小贴士:MMIO全称是Memory-mapped I/O,是一种在CPU和外围设备之间执行输入输出功能的途径。MMIO与内存使用相同的地址总线,CPU用于访问内存的指令也可以直接用于访问I/O设备。CPU会将自己的地址空间预留一块用于I/O设备,而不是物理内存。
PCI Memory Address Range的地址范围定义为4GB至TOLUD(即FFFFFFFFh减去TOLUD地址),由高地址位(FFFFFFFFh)向低地址位延伸。TOLUD全称是Top of Low Usable Dram,这个16bit寄存器由BIOS赋予一个适当的数值,其含义是4GB地址内的物理内存地址顶端。在我们使用4GB内存的时候,这个数值通常会是D0000000h,即3.25GB。而之前图中的系统用的是2GB内存,那么物理内存地址顶端自然就只到7FFFFFFFh(2GB),PCI Memory Address Range也就自动占据了80000000h至FFFFFFFFh这剩下2GB的地址空间。
上图展示了P45芯片组(Intel芯片组)的典型PCI Memory Address Range分配,里面包含了大量系统所必须的内容:High BIOS、DMI总线、FSB中断、APIC、PCIE等多方面的设备地址。这些都是一款Intel芯片组正常运行所必须的东东,尤其是DMI总线(连接Intel芯片组南北桥)管理着主板上的大多数IO设备,它们自然必须在任何时候都享受着MMIO所分配的地址,而这个地址范围通常就是0.75GB。
现在是时候讲一讲主板BIOS中的Memory Remapping(也有的叫Memory Hole Remapping)了。实际上Memory Remapping就是在定义TOLUD的地址(华硕P5Q主板为例),这个功能并不会让任务管理器中显示4GB内存。在使用4GB内存(准确说应该是3.25GB以上内存)并将该功能开启时,TOLUD会被赋值D0000000h,这样MMIO就会被固定在3.25GB至4GB这个范围内,所以我们就能够看到3.25GB的物理内存显示了。
注:每款主板BIOS中的Memory Remapping项含义可能有所不同,其也可能是Memory Reclaim功能的开关。关于Memory Reclaim后文将详细讲述。
DFI的X58主板给出了一个很有意思的选项,名叫Memory LowGap。这个选项可以让用户自定义选择TOLUD的地址,或者说自定义选择PCI Memory Address Range的大小。该选项的范围为1024M至3072M,即PCI Memory Address Range的大小为1024MB-3072MB。一些*显卡的驱动程序会要求比较大的PCI Memory Address Range支持,例如NVIDIA的GTX280、GTX295之类。4GB内存用户甚至可以发现,当更换显卡后,设备管理器显示的物理内存大小竟然也会发生变化,甚至会降低到3GB以下的数值,这就是因为某些高阶显卡申请了更大的PCI Memory Address Range,使得内存的地址空间被进一步压缩,我们可以在设备管理器内看到地址分布的变化。
若PCI Memory Address Range小于驱动程序的需求,那么会导致驱动程序安装失败,这是DFI提供这个选项的原因。关于这个问题应该有两种可能:一是这些高阶GeForce显卡本身确实需求更多的物理地址空间才能正常运作;二是NVIDIA的显卡驱动设计上对高位内存地址考虑不周。不过这两种可能似乎都存在,而NVIDIA也已经正在驱动上慢慢改进这个问题。由于笔者并没有GTX295这样的怪兽显卡可以做尝试,所以无法了解DFI以外的主板是如何解决这个问题的,不过似乎多数主板BIOS都能够应对这个问题。但有一点可以肯定的是,在这种情况下一定要关闭Memory Remapping,因为0.75GB的PCI Memory Address Range基本是不够的。
当我们把DFI X58主板BIOS中的Memory LowGap调至一个巨额的数值之后,上图中的景象就出现了。由于PCI Memory Address Range的进一步扩张,我们发现连2GB的内存竟然也被“侵蚀”了好大一块,50000000h(1280MB)之后的地址就已经开始被PCI Memory Address Range占据。4GB的地址一共就那么多,PCI Memory Address Range占去了,那么内存自然就占不到了。难道内存就这么白费了?真是万恶的PCI Memory Address Range,万恶的MMIO,万恶的美帝国主义。。。。。。先不用着急,继续向下看,我们会把内存找回来的。
寻找失落的内存
让我们再来温习一下这张图,并再次明确一件事情:我们至今为止仍然还是在讲地址,并未谈及任何与内存存储空间相关的东东。PCI Memory Address Range占去的仅仅是物理地址,并不会去占据内存空间。每个内存颗粒中的NAND gates本身并不会拥有地址,所有的地址都是由系统进行分配的。这一切的地址排布与操作系统是多少位并无太多关联,而操作系统方面对PCI Memory Address Range大小的影响主要来自于系统自身驱动以及设备驱动程序等方面的要求。因此我们可以发现在一些默认功能开启较少的系统中(如Win Sever),任务管理器显示的物理内存会大一些。因为此时的PCI Memory Address Range相对较小。从根本上来说,这是芯片组来自于兼容性方面的考量,必须让PCI Memory Address Range位于4GB以内。
由于兼容性的考量,即使使用了64bit操作系统和64bit处理器,PCI Memory Address Range仍然会被芯片组安置于4GB地址以内。所以当安装了大容量物理内存时,PCI Memory Address Range必然会在整个物理内存地址中形成一个Memory Hole。
小贴士:Memory Hole其实很好理解,就像上面的图中那样,Main Memory被分成了两段,而那段被占用的地址空间就像一个“洞”(Hole),所以称之为Hole。。。。。。上面图中PCI Memory Address Range就充当了这个Hole的角色,它并不占用内存存储空间,只是一个物理地址上的横亘,而系统会用其他手段将两段分开的内存地址连接起来。
既然PCI Memory Address Range必须占用这段地址空间,芯片组设计师们自然有其他的考量去解决物理内存地址的分配问题,毕竟会白白浪费内存的芯片组是不讨人喜欢的。既然4GB以下地址如此紧张,我们为何不将物理内存分配到更高的地址空间去呢?于是,TOM、 TOUUD寄存器以及RECLAIMBASE、RECLAIMLIMIT寄存器诞生了。
TOM即“Top of Memory”,其描述的是系统上所安装的物理内存的总量。TOM寄存器值并不见得代表最高内存地址,因为MMIO的地址分配要优先于TOM寄存器,所以内存地址中基本都会存在一些hole(PCI Memory Address Range),这显然会使得TOM寄存器的地址会更高一些。TOM寄存器之下将会有1-64MB内存被Manageability Engine占用(图中的EP-UMA),这是确确实实被占有的内存。
TOUUD即“Top of Upper Usable DRAM”,其描述的是可设定地址的物理内存总量。TOLUD寄存器会始终在4GB内存地址以下工作,但我们知道现在的主流芯片组都能安装高达16GB的内存,TOUUD就可以解决这个问题。TOUUD会在4GB以上地址定义物理内存范围,这个范围会从4GB到可用物理内存顶端(TOM)。经过鉴别的物理内存就可以直接被使用了。
OK,现在我们要回收那块被“占用”的内存地址了。MMIO占据了TOLUD到4GB的地址空间,所以芯片组需要去回收这段被叠加的物理内存。芯片组会开启一个remap window(Main Memory Reclaim Address Range),其底端地址由RECLAIMBASE寄存器定义,顶端地址由RECLAIMLIMIT寄存器定义。然后会将所有落在TOLUD至4GB之间的物理内存回收(映射MMIO),之后安置于4GB至EP Stolen Base的地址空间中,这样我们的内存完完整整的就回来了。
注:由于笔者目前不确定芯片组的Memory Reclaim功能是否可以通过主板BIOS开关,所以某些品牌主板BIOS中的Memory (Hole) Remapping选项可能控制了Memory Reclaim功能的开关。
现在让我们由TOM向下,统计一下物理内存的最终占用情况:Manageability Engine占用1-64MB内存;板载显卡可占用0-256MB内存;板载显卡的GTT(graphics translation table)占用0-2MB内存;TSEG占用0-8MB内存;Legacy Address Range占用1MB内存。除此之外,剩下的内存空间将完全归用户所有。如果是采用非整合芯片组的话,4GB内存用户通常能够拥有4094MB内存空间(见小贴士),我们的内存谁也没动。当然,我们的任务管理器中并不能显示出它们,因为我们的物理地址只有4GB,MMIO会占据一部分地址。不过在实际使用中我们其实能够完整利用那些看不到的内存,那些位于4GB地址以上的内存。想知道究竟?请翻开下一页。
小贴士:相信不少非4GB用户会发现自己的内存同样被偷吃了几MB,比如2GB内存用户通常在设备管理器中只能看到2047MB或者2046MB内存等等。这是因为还有两块地址范围被占据,这两个区域分别是Legacy Address Range和TSEG,他们会使用一部分内存(比如加载系统BIOS)。由于这两个区域都处于TOLUD以下的地址范围内,包含了BIOS的Legacy Address Range更是固定占据00000000h至000FFFFFh的1MB最底层地址空间,所以无论系统安装了多少内存,都会受到影响。
虚拟内存与物理地址扩展(PAE)
Windows的虚拟内存并非简单的指位于我们硬盘上的那个pagefile.sys文件,或者是在内存装不下的时候用于应急的“模拟内存”。事实上Windows的每一个进程都会同时用到物理内存和虚拟内存。
在Windows系统中,任何一个进程都会被赋予其自己的虚拟地址空间(虚拟内存),该虚拟地址空间可以覆盖了一个相当大的范围。对于一个32位进程,其可以拥有的地址空间为2^32=4GB,这使得一个指针可以使用从00000000h到FFFFFFFFh的4GB范围之内的任何一个值。虽然每一个32位进程可使用4GB的地址空间,但并不意味着每一个进程实际拥有4GB的物理地址空间,该地址空间仅仅是一个虚拟地址空间。此虚拟地址空间只是内存地址的一个范围,进程实际可以得到的物理内存要远小于其虚拟地址空间。进程的虚拟地址空间是为每个进程所私有的,在进程内运行的线程对内存空间的访问都被限制在调用进程之内,而不能访问属于其他进程的内存空间(比如声明这是A进程的4GB,那是B进程的4GB)。这样,在不同的进程中可以使用相同地址的指针来指向属于各自调用进程的内容而不会由此引起混乱。
小贴士:简单说物理地址和虚拟地址是不同的两个级别的地址,尽管地址数值会重复(比如都有A0000000h),但处于不同的地址层,所以不会互相影响。
当进程在地址空间中申请出一个“保留区域”后,并不能直接对其进行使用,必须先把物理存储器提交给该区域后,才可以访问区域中的内存地址。在提交过程中,物理存储器按页面边界和页面大小的块来进行提交。这里所说的物理存储器并不局限于计算机内存(优先使用),还包括在磁盘空间上创建的页文件(pagefile.sys),其存储空间大小为计算机内存和页文件存储容量之和(所以Windows自动管理时的pagefile.sys是很大的)。由于通常情况下磁盘存储空间要远大于内存的存储空间,因此页文件的使用对于应用程序而言相当于透明的增加了其所能使用的内存容量。在使用时,由操作系统和CPU负责对页文件进行维护和协调。只有在应用程序需要时才临时将页文件中的数据加载到内存供应用程序访问之用,在使用完毕后再从内存交换回页文件。
进程中的线程在访问位于已提交物理存储器的保留区域的虚拟内存地址时,如果此地址指向的数据当前已存在于物理内存,CPU将直接将进程的虚拟地址映射为物理地址,并完成对数据的访问;如果此数据是存在于页文件中的,就要先将此数据从页文件加载到内存,然后在进行映射之后访问。
说了这么多东东,无论你已经明白虚拟内存的基本知识,还是正在晕头转向,我们只需要明白内存比硬盘快,所以当一个进程的虚拟内存提交的物理存储器是物理内存时,我们就可以省去从磁盘的页文件加载数据到物理内存的时间,程序的工作效率自然就会提高。尽管我们的内存超出了32bit系统的地址结构范围,但我们只要将4GB地址以上的物理内存为虚拟内存所用就不会浪费内存了。
物理地址扩展(PAE)
物理地址扩展(PAE)是早在Pentium Pro时代就有的东东,它可以提高IA32处理器应对4GB以上内存的能力。当启用 PAE之后,Windows操作系统将从两级线性地址转换变为三层地址转换,额外的一层转换用于访问超过4GB地址的物理内存,可以将超出4GB地址的物理内存映射为应用程序进程的虚拟地址空间以提升虚拟内存性能。通过PAE,我们可以完完整整的利用到被回收至4GB以上地址的那部分内存。
至于开启PAE的方法网上遍地都是,我想就不用在这里多费笔墨了。而且事实上,操作系统多数情况下会自动开启PAE,在使用多核心处理器时,无论安装多少物理内存,Windows都会因处理器需要而默认开启PAE功能。换句话说,在这个双核心处理器普及的时代我们基本上不用去考虑PAE的开启问题。
结语:我的内存谁也没动
通过对芯片组地址分配机制的认识,相信各位朋友都已经了解到自己爱机上的4GB内存并非只能用到任务管理器所显示的那3.25GB或者更少,而是已经完整的被利用。同时我们也能够了解到高端显卡对系统地址分配的影响,更换显卡导致任务管理器所示内存容量改变的疑问相信也已经烟消云散。
PAE的开关我们基本上不用担心,而BIOS中的Memory (Hole) Remapping由于可能影响着Memory Reclaim功能,所以笔者建议在各种IO设备(尤其是显卡)正常工作的情况下尽量打开它。
最终,我们的内存谁也没动。我们为了那“失落的”0.75GB内存寻觅许久,而最终却发现它们从来没丢失,这样的结果确实有些耐人寻味啊。
后记:由于目前我们手上没有足够的DDR3内存可以做测试,有条件的朋友可以自己进行一下测试:使用DFI X58主板,安装3GB或者更大内存。将BIOS中的Memory LowGap选项调至3072MB,这样系统任务管理器中所能看到的内存大小就变成了1280MB。此时可以去对比一下实际系统性能,比如运行一些占用内存较大的游戏,或者后台开启一部分驻留内存的程序然后进行3DMark测试。