在動(dòng)態(tài)鏈接下,程序模塊之間包含了大量的函數(shù)引用(全局變量往往比較少,因?yàn)榇罅咳肿兞繒?huì)導(dǎo)致模塊間耦合變大)。所以在程序開(kāi)始執(zhí)行之前,動(dòng)態(tài)鏈接會(huì)消耗不少時(shí)間用于解決模塊之間的函數(shù)引用的符號(hào)查找以及重定位,這也是我們上面提到的減慢動(dòng)態(tài)鏈接的第二個(gè)原因。不過(guò)可以想象,在一個(gè)程序運(yùn)行過(guò)程中,可能很多函數(shù)在程序執(zhí)行完都不會(huì)被用到,比如一些錯(cuò)誤處理函數(shù)或是一些用戶很少用到的功能模塊等,如果一開(kāi)始就把所有的函數(shù)都鏈接好實(shí)際上是一種浪費(fèi)。所以ELF采用了一種叫做延遲綁定(Lazy Binding)的做法,基本的思想就是當(dāng)函數(shù)第一次被用到才進(jìn)行綁定(符號(hào)查找、重定位等),如果沒(méi)有用到則不進(jìn)行綁定。這樣的做法可以大大加快程序的啟動(dòng)速度,特別有利于一些大量函數(shù)引用和大量模塊的程序。ELF 使用PLT(Procedure Linkage Table)的方法來(lái)實(shí)現(xiàn),這種方法使用了一些很精巧的指令程序來(lái)完成。
看到這里想到了iOS 中NSObject類的+load和+initialize這兩個(gè)方法。
在程序啟動(dòng)時(shí),Runtime會(huì)去加載所有的類。在這一時(shí)期,如果類或者類的分類實(shí)現(xiàn)了+load方法,則會(huì)去調(diào)用這個(gè)方法。
而+initialize方法是在類或子類第一次接收消息之前會(huì)被調(diào)用,這包括類的實(shí)例對(duì)象或者類對(duì)象。如果類一直沒(méi)有被用到,則這個(gè)方法不會(huì)被調(diào)用。
基于這兩個(gè)方法的特殊性,我們可以將類使用時(shí)所需要的一些前置條件在這兩個(gè)方法中處理。不過(guò),如果可能,應(yīng)該盡量放在+initialize中。因?yàn)?load方法是在程序啟動(dòng)時(shí)調(diào)用,勢(shì)必會(huì)影響到程序的啟動(dòng)時(shí)間。而+initialize方法可以說(shuō)是懶加載調(diào)用,只有用到才會(huì)去執(zhí)行。