一、應用程序的加載
APP加載過程:程序啟動依次加載dyld
、libSystem
、libdispathc.dyld
、libobjc動態庫
,最終調用_objc_init()
方法,在此方法中Runtime向dyld
注冊回調函數
,加載新的image
,執行map_images
、load_images
,imageLoader
加載image
,調用main
函數
二、dyld動態鏈接器
dyld(the dynamic link editor)是蘋果的動態鏈接器,是蘋果操作系統一個重要組成部分,在系統內核做好程序準備工作之后,交由dyld負責余下的工作。
1.dyld的加載過程:
1.環境變量的配置
2.共享緩存 checkSharedRegionDisable()
3.主程序的初始化
4.加入動態庫 loadInsertedDylib()
5.link主程序 link(sMainExecutable, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1)
6.link動態庫 link(image, sEnv.DYLD_BIND_AT_LAUNCH, true, ImageLoader::RPathChain(NULL, NULL), -1)
7.initializeMainExecutable
運行所有初始化程序
8.main notifyMonitoringDyldMain()
2.reloadAllImages
加載鏡像文件的步驟:
- 實例化主程序
instantiateFromLoadedImage()
,內核會映射到主要可執行文件中,我們需要為映射到主可執行文件的文件,創建ImageLoader
。在此方法中,然后讀取image
,然后addImage()
讀取加載鏡像文件。會先在instantiateMainExecutable()
中,會確認此mach-o
文件中是否具有壓縮的LINKEDIT以及段數。 - 加載插入任何動態庫
loadInsertedDylib(*lib)
,將其讀取為鏡像文件iamge。 - 鏈接庫。先遍歷,讀取image,然后link。在link中,遞歸插入動態加載的鏡像文件。
3.initializeMainExecutable()運行所有初始化程序步驟:
runInitializers()
-
processInitializers
初始化準備。 - processInitializers中,遍歷
iamge.count
,遞歸一個個開始初始化條件images[i]->recursiveInitialization
。 - 在遞歸開始初始化條件中
recursiveInitialization
,通過notifySingle
方法,對單個鏡像通知開始初始化。獲取鏡像文件的真實地址(*sNotifyObjCInit)(image->getRealPath(), image->machHeader())
, 而notifySingle
中的sNotifyObjCInit
是在objc_init()
中注冊傳遞過來的,所以只有當objc_init()
調用時,重新加載image
。 - notifySingle方法之后,遍歷初始化
this->doInitialization(context)
- 在doInitialization方法中,先調用
doImageInit(context)
,確保libSystem庫
必須提前初始化完成。再調用doModInitFunctions()
方法,對 C++和構造函數處理,然后調用libSystem_initializer
方法,調用libdispatch_init
,調用_os_object_init
,最終調用_objc_init
方法。 - _objc_init方法來注冊回調函數,重新加載
images
,執行map_images
、load_images
,imageLoader
加載image
,調用main
函數。
面試題
1.main()之前系統做了哪些工作?
1)dyld 開始將程序二進制文件初始化
2)交由ImageLoader
讀取 image
,其中包含了我們的類,方法等各種符號(Class、Protocol 、Selector、 IMP)
3)由于runtime
向dyld
綁定了回調,當image
加載到內存后,dyld
會通知runtime進行處理
4)runtime
接手后調用map_images
做解析和處理
5)接下來load_images
中調用call_load_methods
方法,遍歷所有加載進來的Class
,按繼承層次依次調用Class
的+load
和其他Category
的+load
方法
6)至此 所有的信息都被加載到內存中
7)最后dyld
發送調main函數
的通知,接下來就是main函數