Raymond Chen 2003年8月14日
太长不看
Windows 95 的内存管理器引导算法的内部工作原理。
简单说
如果你的机器内存高于480MB,Windows 95将无法启动。(在当时,这么大的内存被认为是不可能的。还记得,Windows 95的目标机器是一个4MB的386SX,有16MB的内存都会被认为是高配了。根据摩尔定律,我们在必须处理“超大内存配置”之前还有七年的时间。我的一个朋友在他的机器上装了96MB的内存来测试我们是否会在“巨大内存配置”下崩溃,我们都从嘴角流下了贪心的眼泪。)
到了 Windows 98 ,将限制提高到了1GB,因为有一个厂商(这里就不点名了)疯狂到想要销售装有1GB RAM的机器,并预装 Windows 98 而不是更适合的 Windows NT 。
仔细讲
Windows 95启动过程中发生的第一件事之一,一旦你过渡到32位模式,就是初始化32位内存管理器。但现在你遇到了一个鸡和蛋的问题:内存管理器需要分配一些内存来跟踪它正在管理的内存。(跟踪哪些页面已经加载到内存中,哪些被交换出去,诸如此类的事情。)但在内存管理器初始化之前,它无法分配内存。哎呀!
解决方案是两次初始化内存管理器。
第一次初始化内存管理器时,它从init-data段预分配的固定内存块中获取所有内存。它将这个固定块设置为内存管理器堆。所以现在有一个堆可以用来满足内存分配的需求。
接下来,内存管理器开始在系统中寻找真正的内存,当它找到一些时,它会分配内存(从初始固定块中)来跟踪真正的内存。
在内存管理器找到系统中所有的真实内存之后,就是第二次初始化内存管理器的时候了:它从真实内存中划出一块用作“真实堆”,并将迄今为止一直在使用的堆(固定大小的堆)中的信息复制到“真实堆”中。
一旦所有内容都被复制并且所有指针都被修正,全局内存管理器堆指针被改变指向新的(“真实”的)堆,原来的堆被废弃。
当init-data段被丢弃时(这发生在系统初始化结束时),原始堆所消耗的内存被回收。
由于init-data段的固定块需要足够大以满足内存扫描期间执行的所有内存分配。如果你的内存太多,内存扫描期间的分配就会失败,系统就会停止。
init-data段的大小是为了平衡两个因素而选择的。你做得越大,系统在内存扫描期间遇到分配失败之前就可以拥有更多的内存。但你不能做得太大,否则内存量小的机器甚至无法将VMM加载到内存中。
题外话
时光匆匆,一切当初看起来不可能,不可思议的,现在都是司空见惯。
谁能想到,2024年的今天,主流机器的内存配置都是8~16GB了,真是难为VMM的设计者了。向你们致敬!