在动态链接下,程序模块之间包含了大量的函数引用(全局变量往往比较少,因为大量全局变量会导致模块间耦合变大)。所以在程序开始执行之前,动态链接会消耗不少时间用于解决模块之间的函数引用的符号查找以及重定位,这也是我们上面提到的减慢动态链接的第二个原因。不过可以想象,在一个程序运行过程中,可能很多函数在程序执行完都不会被用到,比如一些错误处理函数或是一些用户很少用到的功能模块等,如果一开始就把所有的函数都链接好实际上是一种浪费。所以ELF采用了一种叫做延迟绑定(Lazy Binding)的做法,基本的思想就是当函数第一次被用到才进行绑定(符号查找、重定位等),如果没有用到则不进行绑定。这样的做法可以大大加快程序的启动速度,特别有利于一些大量函数引用和大量模块的程序。ELF 使用PLT(Procedure Linkage Table)的方法来实现,这种方法使用了一些很精巧的指令程序来完成。
看到这里想到了iOS 中NSObject类的+load和+initialize这两个方法。
在程序启动时,Runtime会去加载所有的类。在这一时期,如果类或者类的分类实现了+load方法,则会去调用这个方法。
而+initialize方法是在类或子类第一次接收消息之前会被调用,这包括类的实例对象或者类对象。如果类一直没有被用到,则这个方法不会被调用。
基于这两个方法的特殊性,我们可以将类使用时所需要的一些前置条件在这两个方法中处理。不过,如果可能,应该尽量放在+initialize中。因为+load方法是在程序启动时调用,势必会影响到程序的启动时间。而+initialize方法可以说是懒加载调用,只有用到才会去执行。