用我们的32位吸脂工具为你的应用程序减肥


Matt Pietrek是《Windows 95系统编程奥秘》(1996,电子工业出版社,IDG) 一书的作者。他在NuMega工作,EMAIL:71774.362@compuserve.com 。

你以为你已经做了一个很恰当、很紧凑的应用软件。你清楚程序中的每一行代码, 而且自信没有多余的东西浪费空间、延缓速度。天啊,就像现在的即食食品, 你的代码中可能隐藏了脂肪成份。也许你所写的代码不用负这个责任, 而是你的编程工具和技巧为你的软件中添加多余的东西,并延缓运行速度。 让我们复习一下可以用来为你的程序减肥的方法。我这里只谈到C和C++程序, 但我所说的也部分的使用适用于其他编译语言,如Delphi等。
《为你肥硕的执行程序吸脂、减肥》(微软系统月刊,1993,7)是我早期的一篇文章, 提出了许多EXE和DLL发胖的原因。那篇文章还提供了一个测试可执行文件并给出它们 相对健康程度的程序:EXESIZE.EXE。那时主要是16位的WINDOWS程序。 既然现在的系统是WINDOWS NT 和WINDOWS 95,我已经收到很多请求, 要求得到能为 WIN32的PE文件工作的新版本的EXESIZE。
因为32位的PE文件与16位的NET文件格式不同,我不能仅仅对EXESIZE 作很小的改动就完事。现在我觉得有必要回头看看为什么提出上一篇文章。 16位NE文件需要的一些单元在WIN32中没有应用,但16位与32位的可执行程序同样 易于在同样的地方冗余,甚至,WIN32还增加了一些增大你EXE、DLL 长度与装入时间的新方法。在这篇文章中,当我提到"可执行文件", 我的意思是所有的WIN32 PE文件,不管是EXE 文件,或DLL文件,或其他。
首先,让我们回顾我为16位程序提出的建议。当我在写这篇文章前我也这样做了, 很高兴地想到相较16位WINDOWS的黑暗时代,WIN32的编程是多么的简单。 另一点来说,一些陈年的问题依然存在,所以,我们用1993年的文章来看看现在的 WIN32的编程世界。
在16位NE文件中正确设定队列(Alignment)。每一段(segment) 和资源都从文件的一个偏移开始。大的16位程序经常有大量的段。 有几十个甚至上百个资源也很普遍。很多的废物就因为缺省连接队列长度为 512字节而引进了。通过配置你的连接器(linker)(在Microsoft linker中用 "/ALIGN:XXX")你可以设定一个更合理的值(典型的是16字节), 很显著的缩小你的文件。
在WIN32的PE文件中,段的等价物是片段(section)。片段依然需要界定 (通常是512字节)。主要的不同是庞大的PE程序一般也不会超过10片段。 而且,一个PE文件中所有的资源都组合到单个片段中,因此,资源的队列不是个问题。
在16位NE文件中不要生成无用的代码。当你引进一个函数,编译程序 (或汇编程序)就在函数的开头和结尾生成一些特别的代码。 这些代码设置数据段选择器,为外部函数的代码选择适当的段。 这里的问题是许多程序所用的编译开关是;为每个远程函数都生成这些特别的代码, 而不是仅为外部函数。很高兴,在WIN32中外部函数不再需要这些特别的代码。
现在是10点钟了,你知不知道你的调试信息在哪儿?这是很重要的, 带着调试信息在可执行文件里的程序表明这是个很蠢的程序员或编程小组。 后面我还将提到这个问题。
实时模式(Real Mode)已经不再使用,你为什么还支持它呢?在MICROSOFT WINDOWS的早期,程序的段可能要在内存中移动,这在保护模式不是一个问题, 因为INTEL的CPU能够通过它逻辑-物理地址转换能力来向你屏蔽;在实时模式, CPU无法做到这点。为了在实时模式下运行时避免出错,程序中经常包括了一些 代码来隐藏段已经移动的事实。
这些代码只有在实时模式下才用的着。很多程序在WINDOWS 3.0 下启动时都指定只能运行在保护模式下,然而他们还包含有从来不用的"实时废物"。 幸运的是,在PE文件中,这个问题已经不复存在。
将多个段打包。前面我提到NE文件经常有很多段。因为一些原因( 我不会提到这些),让连接程序把尽可能多的段合并到单个段中回很有好处。 在PE文件中,不再有段,但它们的替代品(片段)也可以用一些连接程序来合并。 合并片段的好处不同于16位程序中合并段,后面再详细解说。
将你的Relocation连接起来。16位NE程序文档允许多个Relocation 在可执行程序中象单个Relocation那样存在,而不是存在一大堆分离的Relocations。 这个技术叫做链(chainning)。一些连接程序利用了这点,但在我原来那篇文章写作时 Borland的TLINK没有。后来,TLINK已经更新了。
32位PE文件的Relocation完全不同于NE文件。当你不能链PE风格的relocation时, 你就不仅仅缩小可执行文件的长度。后面再说吧。
(抱歉,我真的不知道这个词怎么翻译,而下面几乎整整一章说这个问题, 程序里也有个LookForRelocations( PE_EXE2 & peFile )的函数。哪位帮帮忙, 否则翻译到那一章时就比较麻烦了!救命!)
明智地使用运行库(Runtime Library).
下一页


翻译到了回顾16位程序的倒数第三个忠告,最后两个是:使用BSS(块存储空间); 缩小常驻名表。我没有编过16位程序(对32位程序的理解也不够深),所以在翻译 过程中会有很多不到位的地方,如果您觉得费解,希望马上提出来, 一起探讨一下原文的精髓。
来信留言。您的支持是我的动力。