用我们的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,
很可能这文件就是递增联接的。