關于mach-o
mach-O文件為Mach Object文件格式的縮寫,它是一種用于可執(zhí)行文件,目標代碼,動態(tài)庫,內核轉儲的文件格式。
常見的有以下形式:
- Executable 可執(zhí)行文件
- Dylib動態(tài)庫和Framework動態(tài)庫,對應頭文件和資源文件集合
Apple可執(zhí)行文件格式幾乎都是mach-o;
關于更多mach-o ,可參考Mac OS X ABI Mach-O File Format Reference
關于mach-o數(shù)據(jù)結構,可參考Mac本地路徑下的/usr/include/mach-o源碼。
為了直觀看出mach-o相關信息,可以使用三方工具MachOView
編譯好的工程很老了,建議下載源碼自己運行使用。
關于安裝源碼啟動報錯,可參看別人已經寫好的說明,我這邊就不多說了。
這里我用MachOView工具打開了我本地的一個動態(tài)庫。如圖:

關于 dyld
dyld(the dynamic link editor)是蘋果的動態(tài)鏈接器,在系統(tǒng)內核做好程序準備工作之后,交由dyld負責余下的工作。它代碼是開源的。源碼地址。
在App啟動時它就負責加載mach-o文件。
關于 dyld詳細解析說明,可參考dyld詳解
App 具體啟動流程
App啟動一般分兩種冷啟動和熱啟動:
冷啟動是指, App 點擊啟動前,它的進程不在系統(tǒng)里,需要系統(tǒng)新創(chuàng)建一個進程分配給它啟動的情況。這是一次完整的啟動過程。
熱啟動是指 ,App 在冷啟動后用戶將 App 退后臺,在App 的進程還在系統(tǒng)緩存的情況下,用戶重新啟動進入 App。
這里我們說的主要是冷啟動。
App啟動主要包括三個階段:
1: main()函數(shù)執(zhí)行前
這里就主要是dyld加載mach-o文件了
加載步驟主要分以下幾步:
- 設置運行環(huán)境
主要設置運行參數(shù),環(huán)境變量之類的??梢栽賦code的 Product->Scheme -> EditScheme,配置環(huán)境變量DYLD_PRINT_OPTS和DYLD_PRINT_ENV,通過xcode打印dyld加載各種運行參數(shù)和環(huán)境變量。

- 加載共享緩存
如果共享緩存已加載就不在額外處理。
加載可執(zhí)行文件
主程序的
Mach-O加載進內存,并實例化一個ImageLoader。
ImageLoader是抽象類,其子類負責把Mach-O文件實例化。-
加載動態(tài)庫
會先從共享緩存中搜索
鏈接主程序,進行 rebase 指針調整
將實例化后的主程序進行動態(tài)修正,讓二進制變?yōu)榭烧?zhí)行的狀態(tài)。
Rebase 修正內部(指向當前mach-o文件)的指針指向.Bind 修正外部指針指向
包括鏈接插入的動態(tài)庫,執(zhí)行弱符號綁定。運行時Runtime 初始化
相關類注冊,分類注冊,方法唯一性檢查.
我們可以通過先加符號斷點 斷在_objc_init,就可清晰看到dyld執(zhí)行到runtime初始化
之前的調用了。


我們可以看到:
棧底的dyldbootstrap::start()方法,繼而調用了dyld::_main()方法,再到ImageLoader,再到objc_init。
其他必要的初始化
+load方法,
C/C++靜態(tài)初始化對象和標記為attribute(constructor)的方法
2:main()函數(shù)執(zhí)行后
從main()函數(shù)執(zhí)行開始,到appDelegate 的 didFinishLaunchion里首屏渲染相關方法執(zhí)行完成。
3:首屏渲染完成之后
其他業(yè)務模塊相關代碼初始化,文件處理,業(yè)務監(jiān)聽等等。
App啟動時間優(yōu)化
在Xcode中,可以通過設置環(huán)境變量來查看App的啟動時間,DYLD_PRINT_STATISTICS和DYLD_PRINT_STATISTICS_DETAILS。
通過了解App啟動流程,我們可以做以下優(yōu)化
main()函數(shù)執(zhí)行前:
減少動態(tài)庫數(shù)量,可以合并動態(tài)庫
減少無用的方法和類,合并分類
減少 在load方法,試著用Initialize替代
減少atribute((constructor))的使用,控制全局變量數(shù)量
main()函數(shù)之后:
對業(yè)務進行模塊化處理,非首屏渲染業(yè)務應當盡量放到首屏渲染之后處理。