App的啟動可以分為2種:
冷啟動
(Cold Launch)
從零開始啟動APP熱啟動
(Warm Launch)
APP已經(jīng)在內(nèi)存中,在后臺存活著嚼贡,再次點(diǎn)擊圖標(biāo)啟動APP。
APP啟動時(shí)間的優(yōu)化秩霍,主要是針對第一種齐婴, 即冷啟動 進(jìn)行優(yōu)化茄厘。
啟動時(shí)間分析
通過添加環(huán)境變量,可以打印出APP的啟動時(shí)間分析:
(Edit scheme -> Run -> Arguments) 在環(huán)境變量欄谈宛,將DYLD_PRINT_STATISTICS
設(shè)置為1次哈。如果需要更詳細(xì)的信息,那就將DYLD_PRINT_STATISTICS_DETAILS
設(shè)置為1吆录。
APP冷啟動
APP的啟動由dyld
主導(dǎo)窑滞,將可執(zhí)行文件加載到內(nèi)存,順便加載所有依賴的動態(tài)庫恢筝。并由runtime
負(fù)責(zé)加載成objc定義的結(jié)構(gòu)哀卫,所有初始化工作結(jié)束后,dyld就會調(diào)用main
函數(shù)撬槽。接下來就是UIApplicationMain
函數(shù)此改,AppDelegate
的application:didFinishLaunchingWithOptions:
方法。
分為四大階段:
dyld
加載可執(zhí)行文件侄柔,動態(tài)庫(遞歸加載)
runtime
main()
函數(shù)執(zhí)行后
首屏渲染完成后
1.關(guān)于dyld
https://blog.csdn.net/zy_flyway/article/details/92835911
dyld(the dynamic link editor)
是蘋果的動態(tài)鏈接器共啃,是蘋果OS一個重要組成部分,在系統(tǒng)內(nèi)核做好程序準(zhǔn)備工作之后勋拟,交由dyld負(fù)責(zé)余下的工作勋磕。而且它是開源的,可以了解到系統(tǒng)加載動態(tài)庫的細(xì)節(jié)敢靡。
共享緩存機(jī)制
在iOS系統(tǒng)中挂滓,每個程序依賴的動態(tài)庫,都需要通過dyld 一個一個加載到內(nèi)存啸胧。然而赶站,很多系統(tǒng)庫幾乎是每個程序都會用到的。如果在每個程序運(yùn)行的時(shí)候都重復(fù)的去加載一次纺念,勢必造成運(yùn)行緩慢贝椿。為了優(yōu)化啟動速度和提高程序性能, 所有默認(rèn)的動態(tài)鏈接庫被合并成一個大的緩存文件陷谱,放到/System/Library/Caches/com.apple.dyld/
目錄下烙博,按不同的架構(gòu)保存分別保存著。
2.Runtime
啟動APP時(shí)烟逊,runtime把可執(zhí)行文件和動態(tài)庫加載到內(nèi)存渣窜,以便管理。
調(diào)用
map_images
進(jìn)行可執(zhí)行文件內(nèi)容的解析和處理
在load_images
中調(diào)用call_load_methods
宪躯,調(diào)用所有Class和Category的+load方法乔宿,進(jìn)行各種objc結(jié)構(gòu)的初始化(注冊O(shè)bjc類 、初始化類對象等)
調(diào)用C++靜態(tài)初始化器和attribute((constructor))
修飾的函數(shù)访雪。
到此為止详瑞,可執(zhí)行文件和動態(tài)庫中所有的符號(Class掂林,Protocol,Selector坝橡,IMP泻帮,…)
都已經(jīng)按格式,成功加載到內(nèi)存中驳庭,被 runtime 所管理刑顺。
3.main函數(shù)執(zhí)行后
指的是從main()
函數(shù)執(zhí)行開始,到 appDelegate
的 didFinishLaunchingWithOptions
方法里 首屏渲染相關(guān)方法執(zhí)行完成饲常。
首屏初始化所需配置文件的讀寫操作
首屏列表大數(shù)據(jù)的讀取
首屏渲染的大量計(jì)算等
App啟動優(yōu)化
按照 不同階段來進(jìn)行優(yōu)化
dyld
1.減少動態(tài)庫蹲堂、合并一些動態(tài)庫。減少動態(tài)庫加載贝淤。每個庫本身都有依賴關(guān)系柒竞,蘋果公司建議使用更少的動態(tài)庫,蘋果最多支持6個非系統(tǒng)的動態(tài)庫合并為一個播聪。(定期清理不必要的動態(tài)庫)
2.減少Objc類朽基、分類的數(shù)量、減少Selector數(shù)量(定期清理不必要的類离陶、分類)
3.減少C++虛函數(shù)數(shù)量稼虎, 減少C++全局變量的數(shù)量
4.Swift盡量使用structruntime
用+initialize
方法和dispatch_once
取代所有的attribute((constructor))
、C++靜態(tài)構(gòu)造器招刨、ObjC的+load
霎俩。因?yàn)樵谝粋€+load()方法里,運(yùn)行時(shí)進(jìn)行方法替換操作沉眶,會帶來4毫秒的損耗打却。main() 函數(shù)執(zhí)行后
main()函數(shù)開始執(zhí)行后,到首屏渲染完成前谎倔,只處理首屏相關(guān)的業(yè)務(wù)柳击。其他的非首屏業(yè)務(wù)的初始化,監(jiān)聽注冊片习,配置文件讀取放在首屏渲染完成后去做捌肴。其他
在不影響用戶體驗(yàn)的前提下,不要將延遲操作全都放在finishLaunching
方法中藕咏。 按需加載状知。
不使用xib,直接視用代碼加載首頁視圖侈离。
NSUserDefaults
實(shí)際上是在Library目錄下會生產(chǎn)一個plist文件试幽,如果文件太大筝蚕,一次能讀取到內(nèi)存中可能很耗時(shí)卦碾。
每次用NSLog
打印會隱式的創(chuàng)建一個Calendar铺坞,因此需刪減啟動時(shí)各業(yè)務(wù)方的NSLog
,或者僅僅針對debug版輸出log洲胖。
啟動時(shí)济榨,發(fā)送的所有網(wǎng)絡(luò)請求。
ipa安裝包瘦身(主要由可執(zhí)行文件绿映、資源組成)
資源(圖片擒滑、音頻、視頻等)采取無損壓縮叉弦,去除沒有用到的資源丐一。
可執(zhí)行文件瘦身:
編譯器優(yōu)化Strip Linked Product、Make Strings Read-Only淹冰、Symbols Hidden by Default設(shè)置為YES
去掉異常支持Enable C++ Exceptions库车、Enable Objective-C Exceptions設(shè)置為NO
,Other C Flags添加-fno-exceptions
編寫LLVM插件檢測出重復(fù)代碼樱拴、未被調(diào)用的代碼
可借助第三方工具解析LinkMap文件: https://github.com/huanxsd/LinkMap
檢測App耗時(shí)
抓取主線程的方法調(diào)用堆棧柠衍,計(jì)算一段時(shí)間各個方法的耗時(shí),Xcode自帶的Time Profiler晶乔。對objc_msgSend方法進(jìn)行hook來掌握所有方法的執(zhí)行耗時(shí)