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


明智地使用运行库(Runtime Library). 如果你是用C++之类的编译语言, 你应该联接一些外部的常规库。这些常规库一般叫做运行库(RTL)。 如果你选择静态联接这些常规库(而不是使用DLL文件),你的代价是执行文件的长度。 一般的,你可能为你所使用的每一个 增加了RTL的几个字节到几K 字节的多余的代码和数据。有些简单的函数如strcpy 非常小, 然而有些象printf 那样复杂的就会大得多。
在我原来那篇吸脂机的文章里,我要求人们使用通用的RTL函数的Windows版本, 而不要联接静态版本。在Win32这一点同样适用。实际上,Win32的API包含了 Windows 3.1中没有的C/C++类函数的一个扩展集,这使得减少你的可执行文件长度, 用系统DLL里的代码来工作成为可能。
例如,当你要在代码中用sprintf时,你可以选用wsprintf代替。 它能从你的程序中减少几千字节的RTL代码。同样,像strcpy那样的函数可以用 lstrcpy代替,在程序中用malloc和free会增加几千字节代码和数据, 应该考虑用HeapXXX(如HeapAlloc,HeapFree等)代替。可以参照我的关于这个问题的 《在钩子下》( Under the Hood)专栏。

用BSS段。在16位编译程序中,未初始化的数据(定义却没给初始值的变量) 都放在称为BSS段的地方。(假设你们知道什么是BSS。)既然BSS段的数据不包含任何 特别的初始值,16位联接程序一般把BSS段的数据连接入主数据段, 这样不需要任何磁盘空间。16位连接程序可以设置段记录中磁盘空间的长度小于 内存的长度。在Win32对未初始化的数据也可以同样运用,虽然是片断而不再是段。 后面我还将说到这一点。
随便说一句,如果你还是迷惑,BSS的意思是块存储空间(block storage space)。

缩小你的常驻名表(按顺序输出)。在编16位Windows程序时, 当你调用或输出DLL的函数时,连接程序一般按顺序查找函数。“按顺序” 也就是“按数字顺序”的另一个说法。也就是说,每个所调用的函数用一个 WORD值来识别。除了按数字顺序输出外还可以按名字输出, 函数的实际名字出现在调用的可执行文件和被调用的文件中。显然, 按顺序的工作效率比按函数名工作要好。函数名字一般比较长, 所以它们要用比按顺序更多的空间和工序。
为了按名字输入(很少在16位Windows使用),目标DLL必须按名字输出函数。 输出的名字将是这两种表之一:常驻名表和非常驻名表。 常驻名表的缺点是它占内存,而非常驻名表却不。不幸的是, 很多16位连接程序在某些情况下缺省地把输出名字放到常驻名表里。
基于Win32的程序已经没有常驻名表和非常驻名表的概念, 只有一个放置输出函数名的表。但输出函数名占据空间的问题依然存在。 输出函数名和输入函数名都在内存中,除非你尽力地按顺序输出你的函数。 你能够按顺序输入和输出你自己的可执行程序,但按顺序来输入系统DLL 函数并不是一个好注意,因为交叉平台的函数顺序不一定相同。

回到现在
16位、32位的比较就到这里。在回顾中,我重点提出了我的32位版本 EXESIZE程序可以运用的领域。但在可以大踏步前进的地方我们为什么还要 小心翼翼的踩水呢?有一个可以提高的地方是实时性能。记住这一点: 我已经把我的新的吸脂工具的技巧分为两方面,空间、性能。
后面我将奉献一个32位的工具,让你看看如何缩小你的程序,并提高性能。 但在品尝甜点之前,让我们先进餐。让我们考察一些空间和性能的要点, 这样你能更好的理解吸脂工具的好处。
第一套技巧用来为你的程序节省空间,这通常是值得的。每一个规律总有例外, 但我想你要找出这些技巧的例外可不容易。
Visual C++中我很喜欢的一个特点就是递增联接(Incremental Linking)。 减少联接程序的工作,能使Visual C++在几秒中就完成联接。 递增联接是调试时的缺省设置。
递增联接只重写从上次联接之后改动过的部分,因此获得这个令人眩目的性能。 为了达到这个目的,Microsoft Link拷贝了一大堆INT 3指令到可执行文件的 不同部分之间。因此当你在源代码加了几句后,多出来的代码就覆盖了INT 3 所在的空间。文件的其他部分没有变动。
正如你想象的,递增联接的代价也很大,就是可执行文件的长度。 一个使用递增联接的文件可以(平均的)用1/3的空间来存放INT 3。 在大的执行文件中,这很可能给你增加几百KB甚至几M的INT 3!
怎样解决呢?在你编译发行版本时确认关掉递增联接功能。问题是, 我已经见过很多不区分不同版本的程序员。他们把测试时的文件 (也就是调试版本)发布出去了。我的32位吸脂工具可以在这些文件 中挑出可执行部分和浪费的部分。如果你在一个可执行文件里看见了一堆INT 3, 很可能这文件就是递增联接的。


下一页