app的啟動過程(三)

大神蝦發表於2019-03-15

這是戴老師釋出的第三篇,正經發布的第一篇。看了1天以後我就想說,我要不還是去賣人蔘吧,太難了!這以後我要是全學會了我有立刻辭職去阿里的衝動。當然了,我除了在學習裡面的知識,我還在想1個問題。

為什麼他會我不會?

這個問題的扯淡程度直逼他的答案的扯淡程度,我覺得我不會的原因是因為很大一段時間我覺得學了沒用。按照文章的優化方法,我們那個小破app啟動頂多能縮短個幾百ms,因為本來app就簡單。但是縮短個幾百ms對於1個app沒用對於技術有用麼?這要涉及到學習方法。

我自己總結的學習方法是這樣的:比如你要學一門新的語言,你要買1本基礎書。有人說基礎啥的你上網查不就得了?但是別忘了,你沒學過你連查啥都不知道。還有就是學基礎的時候別查的太深,這個階段以用為主。等過了這個階段,開始查漏補缺,進行深入進階。這也是我學習戴老師課程的原因。所以縮短個幾百ms,可能用app的人感覺不到,但是這個技術不理解,我看我下一章也不用看了。

正文開始,app的啟動過程

我們首先將app分為冷啟動和熱啟動,熱啟動顧名思義,人家都熱了,說明啟動一遍了,可能在後臺啥的,這個階段能做的事很少,我們不研究。我們從冷啟動開始說,冷啟動我們又分為三個階段

1. main()函式執行前。這個階段我們主要有以下幾個部分(1)載入可執行二進位制檔案mach-o檔案(昨天的查漏補缺一直就是針對的這個)(2)載入動態庫連結器dyld,dyld是個專門用來載入動態連結庫的庫。執行從d yld開始,dyld從可執行檔案的依賴開始,遞迴載入所有的依賴動態連結庫。動態連結庫包括iOS用到的所有系統Framework,載入OCruntime用到的libObjc,系統級別的libSystem,例如libdispatch(GCD)和libsystem_blocks(Block),進行 rebase 指標調整和 bind 符號繫結 (3)Objc進行類的註冊,確定方法的唯一性 (4)初始化執行load方法,attribute((constructor)) 修飾的函式,建立C++全域性靜態變數。

好了,這些東西就足夠我們研究一陣子的了。我們先說一下什麼是Mach-o檔案,mach-o就是Mach Object。官方給的Mach-o檔案非常複雜,裡面有啥啥啥的看不懂的東西,就是已經細微到暫存器的東西,我實在研究不通。就只按我自己的理解來說,Mach-o檔案其實就是一些檔案的集合:裡面有二進位制檔案,型別為Excutable,裡面還有動態庫檔案dylib,裡面還有捆綁包,bundle包,一種特別的動態庫,只能在執行時執行。Framework檔案,是包含資源或者標頭檔案的靜態庫或者動態庫。那麼mach-o檔案在哪裡看呢,我找了半天就是沒找到。後來才知道,一般的framework裡面都有.o檔案但是你是看不到的,你需要用一個叫MachOView的軟體開啟它才能看見裡面的.o檔案否則你看到的可能就是這樣的

app的啟動過程(三)

這是百度人臉識別的SDK,反正我是沒找到什麼.o檔案。但是我們好像換一種方法看不到,能摸到:

app的啟動過程(三)

這樣我們確實看到它是1個mach-o檔案了哈,但是再深入的我就沒有研究了。

下面我們在研究下什麼叫rebase指標調整和bind符號繫結。首先我們確定一下這個是動作是誰做的。是dyld做的。dyld是什麼?動態庫聯結器。怎麼樣連結動態庫?為什麼要連結動態庫?因為載入了mach-o二進位制檔案後,動態庫是獨立的,dyld要將所有動態庫繫結起來。mach-o動態庫上面要寫上要繫結的動態庫的指標和資料,用來修正(fix-up),修正有兩種型別,一種叫rebasing,一種叫binding。為什麼要修正呢?據說在iOS4.3以前不需要修正,後來有了ASLR(address space layoutrandomization)的存在,可執行檔案和動態連結庫在虛擬記憶體中的載入地址每次啟動都不固定,所以需要這2步來修復映象中的資源指標,來指向正確的地址。 rebase修復的是指向當前映象內部的資源指標; 而bind指向的是映象外部的資源指標。 第三點進行類的註冊優化起來就很明瞭,就是我們儘可能減少類的數量,就可以減少載入時間。第四個,初始化執行load方法也很簡單就是少些+load()方法,attribute((constructor)) 修飾的函式呼叫就是1個函式可以在main函式之前呼叫,有什麼作用還不清楚,我沒用過,如圖:

app的啟動過程(三)
輸出為:

app的啟動過程(三)

C++全域性變數就類似於這種,如圖:

app的啟動過程(三)

2. main()函式執行後。main() 函式執行後的階段,指的是從 main() 函式到 appDelegate 的 didFinishLaunchingWithOptions方法裡首屏渲染相關方法執行完成。這裡面要寫的東西我們大家就很熟悉了,一般就是初始化首屏架構,一些第三方的初始化,但是其中我們應該區分開,哪些是首屏渲染之前應該寫的,哪些可以在使用功能的時候才開始。另外關於這個首屏初始化沒有1個固定的說法,有些人認為到首頁viewDidAppear出現了才算,有的人認為走完了didFinishLaunchingWithOptions就算,看個人理解吧。

相關文章