DOS游戏怀旧全攻略 第三章 内存的结界

内存的问题是我们能否运行游戏的关键,没有声音还好办,好歹游戏还能玩;内存出错可就惨了,给面子的来个xxx Error,不给面子的干脆死机!为了能把问题讲的更清楚些,这里老狼先介绍一下混蛋微软的内存管理,有相关基础的兄弟和不想浪费时间的玩友不妨跳过这一段。以下内容老狼参考了不少资料,涉及到微机原理相关内容,如有不妥之处还请各位指正。

1、结界的历史

1979年,Intel推出了具有20根数据总线的8088芯片,寻址能力为1MB,并且受到了IBM的扶植。另一方面,Microsoft在为基于8088的电脑设计的操作系统DOS中,采用了“段内寻址”的方式,每个段的长度为64K字节,共有65535个段,但是因为段与段之间可以互相重叠,段的起始地址间距为16字节,所以DOS的寻址能力只有65535*16Byte,也就是1MB。然而,IBM认为1MB实在太大了,没有人会用到那么多的内存,于是又把384K内存(UMB,Upper Memory Block)分配给ROM BIOS和视频内存等等,于是,邪恶的640K结界形成了,出于兼容性的考虑,此后的DOS一直保留着原有的内存管理机制。这个640K的Base memory,又叫Conventional memory,是系统最基本内存,它是DOS和所有程序都可以用的内存区,被称为常规内存。它是系统内存中最宝贵、最紧张的资源,如果一个程序因为内存不够而无法运行,大多是因为这部分空间不够使用造成的。

随着硬件的发展,80386DX已经是32位微处理器,实际寻址能力达4GB,反观旧的内存管理规范却处处碍手碍脚,于是扩页内存Expanded memory规范横空出世,取代了INT 15H,使程序能够访问32MB的内存空间。EMS通过一种页面映射分配技术的反复映射访问所有的EMS内存,这样的效率并不高,所以只有少数老游戏使用了EMS,比如《魔神战记2》。由于EMS并没有解决根本的问题,Microsoft又制定了扩展内存Extended memory管理规范XMS,通过在实模式与保护模式之间的快速切换,使程序在保护模式中能够直接使用系统所有内存,从而快速访问XMS。XMS简单而实际,被众多DOS游戏采用。我们打破了结界吗?还没有!很多游戏采用了一个signed integer来存储XMS的数量,导致32767以上的数值变成负数,这就要求我们降低内存数量了。唉,如果说640K的结界是天灾,这个signed integer的结界就是人祸了。

再后来,人们终于找到了理想的突破640K结界的方法:使用DOS保护模式(DOS Protected Mode)。80386及以后的CPU在电脑启动后都会进入实模式(Real Mode),以兼容早期的8088。当运行在保护模式中时,CPU的直接寻址能力高达4GB,并且提供了很多高级功能,使程序可以直接使用系统所有的内存资源,常规内存、扩页内存和扩展内存统统失去了意义;并且,保护模式能够充分发挥32位CPU的威力,极大的提高了效率。常玩游戏的各位一定对DOS4GW非常熟悉,它是Watcom C/C++专用的内存管理工具,可以使程序运行在32位保护模式下。著名的《金庸群侠传》就是用了这个DOS扩展器。运行在32位保护模式下的游戏很少遇到内存问题,只可惜这样的游戏真是不多啊。

2、贤者的符咒

这里我们将结合config.sys中内存的有关设置,结合具体游戏来介绍突破内存结界的方法。config.sys是DOS的主要配置文件,放在系统盘的根目录下。

一个典型的config.sys,可以适应多数游戏:

①device=c:\dos\himem.sys /testmem:off
②device=c:\dos\emm386.exe ram
③devicehigh=c:\dos\ide.sys /d:MSCD000
④dos=high,umb
⑤files=30
⑥buffers=30
⑦stacks=9,256

为了方便解释,老狼在行首加了行号。

①himem是XMS存储器的管理驱动程序,它的主要功能是把扩展存储器按XMS规范来管理,也就说,它把传统的扩展存储器改造成了XMS存储器。此外,HIMEM.SYS可以建立HMA(High Memory Area)存储器供DOS使用。如果运行游戏时显示:XMS not found! 这就是因为没有加载himem.sys所致。为了加快启动的速度,可以在后面加上 /testmem:off 参数,跳过内存检测。另外,加上 /cpuclock:on 可以修正系统时钟速度变化的错误。

②emm386是EMS的管理驱动程序。它的功能是把XMS存储器模拟成EMS存储器来使用,并且建立UMB存储器。后面的ram参数表示同时建立UMB和EMS存储器,如果你确定游戏不需要EMS内存,可以考虑把ram换成noems参数,这样可以获得更多的UMB空间。但如果运行游戏时显示:Error: No EMS found!!! 也就是说游戏要求使用ems,你就不能用noems参数了。如果运行游戏时显示:Error: Free memory is not enough 570k,或Base memory not enough,这是常规内存不足,应该考虑减少常驻内存的程序或将程序加载到UMB中。

③devicehigh=c:\dos\ide.sys /d:MSCD000,这是光驱的驱动程序,devicehigh表示把程序加载到UMB中,这样可以为常规内存腾出更多的空间。如果你不需要在DOS下使用光驱,这行可以省略。

④dos=high,umb,设置DOS占用的内存,high表示把DOS核心部分装入HMA以节省常规内存,umb表示允许DOS与UMB建立联系,以便装载TSR程序或设备驱动程序到UMB中,若改成noumb则表示不允许使用UMB。

⑤files=30,设定程序可以同时打开的最大文件数,若不写这一行,相当于默认值files=10,可能导致大型程序运行失败。

⑥buffers=30,设定缓冲区数量。DOS默认缓冲区数Buffers的值为15,每个Buffer占523字节。如果设定了DOS=HIGH,Buffers会移到HMA中,这当然是好事,但是如果用户自己设定的Buffers太大,超过47个,则HMA装入DOS核心后的剩余空间无法容纳,就把全部Buffers移至常规内存中,这将得不偿失,30的数量比较合理。buffers还可以在后面加上一个数字,表示高速缓冲区数量,如buffers=20,8。老狼没感觉到这个选项对游戏有什么影响,也就没有使用过这种设置,所以就不管它了。

⑦stacks=9,256,设定使用的堆栈的数量。第一个数字是堆栈数量,第二个是每个堆栈的大小。通常指定的值是9,256,这个值可以满足大多数的需求。

只有这些显然是不够的,让我们再来看看其他可能遇到的内存问题。如果运行游戏时显示:EMM386 has detected error #xx in an application at memory address xxxx:xxxx. To minimize the chance of data loss, EMM386 has halted your computer. For more information, see the readme.txt file. To restart your computer, press enter. 这多半已经死机了,不过根据老狼的经验,出现这种错误偶然成分居多,就好像windows的非法操作一样,重新启动后多半就能恢复正常。如果还是不行,可能是EMM386的设置有问题,可以根据游戏的要求,对其进行修改,遇到具体问题时我们再讨论。

下面是本章的重点,很多玩友在玩游戏时收到的错误信息是 XMS = -xxxxx,Error: XMS is not enough xxxk,冤枉啊,内存怎么成了负数呢?其实这是因为xms太大,而很多老游戏偏偏采用了一个signed integer来存储xms的数量,导致32767以上的数值变成负数。解决的办法有很多,如果你的内存是64M,你可以在运行游戏之前运行lh smartdrv 32768 16384,加载高速磁盘缓冲程序。lh表示将smartdrv读入UMB,32768表示使用的内存数量(KB),16384表示提供给windows的缓存数量。这样一来,既减少了内存,又增加了系统效率,一举两得。为什么高于64M内存的电脑不能使用这种办法呢?因为smartdrv的缓存越大,它本身占用的空间也就越大,如果UMB容不下它,他会毫不客气的抢占常规内存,直接导致游戏无法运行。实际上,加载带/x参数的smartdrv可以极大的提高游戏性能,所以它是我们必备的法宝。

还有一种办法是使用虚拟硬盘程序,将内存虚拟成硬盘,用很小的常规内存或UMB就可以轻松占用掉大量XMS,很适合大内存的玩友使用。DOS中自带的ramdrive.sys必须在config.sys中加载,一旦加载就不可调整内存盘的大小或删除。而且虚拟硬盘有容量限制,不能超过32M,它们自己还占用较多的常规内存。幸好有人开发了完美的虚拟硬盘软件XMSDSK,这个小东西的好处太多了,它可以在命令行方式下无限次动态调节虚拟硬盘的大小,并可以随时卸载;它占用内存相当才几百字节,而且能够自动调入到UMB,而不需用LH命令,最重要的是,它支持极大的内存,目前高达2G!XMSDSK的使用非常简单,只需执行xmsdsk xxxxx就行了,单位是KB。卸载的命令是xmsdsk /u,非常轻松。下载地址是http://firststep.ahwww.com/dosware/xmsdsk.exe。

如果你打算在windows下玩老游戏,以上问题的解决就更简单了,直接编辑游戏可执行文件的属性,点“内存”,然后按照需要选择合适的内存数量即可。但你可能要忍受无声甚至噪音的痛苦,而且多数游戏的时钟会有所变化。

另外,通过himem.sys调用int 15h也可以限制内存,但15h中断很不安全,微软早已放弃使用了,而且从未公布himem的int 15h用法,所以这种办法不推荐使用,有兴趣的朋友可以自己查阅相关资料。

到这里,我们不妨编一个批处理文件来简化我们玩游戏的过程,建立一个扩展名是bat的文件,在里面输入如下内容(假定你的内存是256M):

lh c:\dos\smartdrv.exe /x
lh c:\dos\xmsdsk.exe 240000 /y
lh c:\dos\mouse.com

以上的路径和程序请根据个人的需要修改。

到这里,相信大家在内存方面不会遇到什么障碍了,多数游戏已经能够运行起来,至于怎么让游戏运行得有声有色、原汁原味,敬请期待后几章的内容。

以上。
怀旧的老狼