本系列博客是本人的源碼閱讀筆記,如果有 iOS 開發(fā)者在看 runtime 的璧疗,歡迎大家多多交流坯辩。為了方便討論,本人新建了一個微信群(iOS技術(shù)討論群)崩侠,想要加入的漆魔,請?zhí)砑颖救宋⑿牛簔hujinhui207407,【加我前請備注:ios 】却音,本人博客http://www.kyson.cn 也在不停的更新中改抡,歡迎一起討論
本文完整版詳見筆者小專欄:https://xiaozhuanlan.com/runtime
背景
在文件objc-runtime-new.m
中,給如下代碼打個斷點:
可以看到調(diào)用棧中有如下函數(shù):
static_init()
以及
_objc_init()
這是我們很熟悉的兩個方法:_objc_init()是上篇文章中說的系瓢,static_init()方法是在_objc_init()中被調(diào)用的阿纤,其定義如下:
/***********************************************************************
* static_init
* Run C++ static constructor functions.
* libc calls _objc_init() before dyld would call our static constructors,
* so we have to do it ourselves.
**********************************************************************/
static void static_init()
{
size_t count;
Initializer *inits = getLibobjcInitializers(&_mh_dylib_header, &count);
for (size_t i = 0; i < count; i++) {
inits[i]();
}
}
通過其注釋,我們大概知道static_init函數(shù)的作用是運行C++的靜態(tài)構(gòu)造函數(shù)夷陋。其原因在于dyld調(diào)用我們的靜態(tài)構(gòu)造函數(shù)晚于libc調(diào)用_objc_init函數(shù)欠拾。這句話咋一看比較難理解,更讓人難以理解的是骗绕,在斷點錢并不是static_init函數(shù)藐窄,而是一個方法:_GLOBAL__sub_I_objc_runtime_new,筆者進入該斷點看到如下內(nèi)容:
可以看到爹谭,里面有好多類似于
__cxx_global_var_init
的方法枷邪。
那么,這些方法又是做什么的呢诺凡,這是本文討論的問題东揣。
分析
為了解釋上面的代碼,我們做個實驗腹泌。
在XCode的main.m文件中輸入以下代碼:
class Person{
public:
Person(){
printf("Person::Person()");
}
~Person(){
printf("Person::~Person()");
}
};
Person kyson;
int main() {
return 0;
}
執(zhí)行后會打印如下結(jié)果:
Person::Person()Person::~Person()
說明執(zhí)行了Person類的構(gòu)造函數(shù)以及析構(gòu)函數(shù)嘶卧。如果讀者對C++的構(gòu)造函數(shù)以及析構(gòu)函數(shù)還有任何疑問的話,可以大概了解一下C++的語法凉袱。筆者的側(cè)重點在于芥吟,我們只是聲明了:
Person kyson;
為什么會執(zhí)行構(gòu)造函數(shù)以及析構(gòu)函數(shù)呢钟鸵。稍微debug一下蒙袍,我們居然發(fā)現(xiàn)狠怨,Person kyson;
這句代碼居然比main()函數(shù)提前執(zhí)行叼风。這有悖于我們之前了解的只有l(wèi)oad函數(shù)早于main()函數(shù)執(zhí)行的常識取董。那么无宿,main()函數(shù)執(zhí)行之前茵汰,系統(tǒng)究竟執(zhí)行了哪些操作,哪些我們能hook呢孽鸡。帶著這個疑問估盘,我們深入研究一下C++的全局變量。
C++ 全局變量初始化
本文完整版詳見筆者小專欄:https://xiaozhuanlan.com/runtime
實驗
在objc_init()方法中刪掉
static_init();
這一行攀细,會發(fā)現(xiàn)程序有崩潰慨削,崩潰的調(diào)用棧如下:
看右下角可知张遭,其崩潰在方法pthread_rwlock_wrlock
中。而這正是因為我們刪掉static_init()后
rwlock_t runtimeLock;
rwlock_t selLock;
mutex_t cacheUpdateLock;
recursive_mutex_t loadMethodLock;
這四行代碼沒有執(zhí)行引起的(因為對應(yīng)的構(gòu)造函數(shù)不能執(zhí)行)地梨。至此謎題終于解開了菊卷。
結(jié)論
本文從C++的全局變量的角度來研究了static_init()的作用,希望大家有所啟發(fā)宝剖。
參考
深入解構(gòu)iOS系統(tǒng)下的全局對象和初始化函數(shù)
廣告
我的首款個人開發(fā)的APP壁紙寶貝上線了洁闰,歡迎大家下載。