iOS開發(fā)之runtime(15):static_init()提升啟動速度

logo

本系列博客是本人的源碼閱讀筆記,如果有 iOS 開發(fā)者在看 runtime 的,歡迎大家多多交流孝扛。為了方便討論,本人新建了一個微信群(iOS技術(shù)討論群)岭洲,想要加入的,請?zhí)砑颖救宋⑿牛簔hujinhui207407雁竞,【加我前請備注:ios 】钦椭,本人博客http://www.kyson.cn 也在不停的更新中,歡迎一起討論

本文完整版詳見筆者小專欄:https://xiaozhuanlan.com/runtime

背景

static_init()方法我們已經(jīng)談?wù)摰暮芏嗔吮摺=裉焓亲詈笠黄v解static_init()文章彪腔,做一個補充。我們再回顧一下方法static_init():

static void static_init()
{
    size_t count;

    Initializer *inits = getLibobjcInitializers(&_mh_dylib_header, &count);
    for (size_t i = 0; i < count; i++) {
        inits[i]();
    }
}

其中进栽,_mh_dylib_header之前的類型是mach_header_64之前也有講解過德挣。不過這里不需要再去賦值,因為它是個extern對象(全局對象)快毛。
接下來著重解決讀者可能存在的幾個問題:

  • Initializer是什么
  • initsi; 這么寫的依據(jù)(含義)

分析

Initializer的聲明如下:

using Initializer = void(*)(void);

這里 using的用法稍加介紹格嗅,主要有三個作用:

  1. 命名空間的使用
    常見的如:
using namespace std;
  1. 在子類中引用基類的成員
class Person {
public:
    Person() :value(55) {}
    virtual ~Person() {}
    void test1() { cout << "Person test1..." << endl; }
protected:
    int value;
};
 
class Man : private Person {
public:
    //using Main::test1;
    //using Main::value;
    void test2() { cout << "value is " << value << endl; }

基類中成員變量value是protected,在private繼承之后唠帝,對于外界這個值為private屯掖,也就是說Person的對象無法使用這個value。

  1. 別名指定
    即是本例中的用法襟衰,這個讓我們想起了typedef贴铜。那么using 跟typedef有什么區(qū)別呢?哪個更好用些呢瀑晒?這里不展開講了绍坝,有興趣的讀者可以參考這篇文章

繼續(xù),我們還是看Initializer 定義:

using Initializer = void(*)(void);

里的void(*)(void);作用苔悦。要說明這個問題轩褐,我們可以一步步分析:

void f(void)

這個不用多介紹,聲明一個返回類型為空玖详,參數(shù)為空的函數(shù) f把介;
那么

void (*p)(void)

就是聲明一個指針p勤讽,該指針指向一個返回類型為空,參數(shù)為空的函數(shù)拗踢。
最后地技,繼續(xù):

(void (*)(void))

就是表明這個指針是個指向一個返回類型為空,參數(shù)為空的函數(shù)秒拔。這下大家應(yīng)該了解了,

inits[i]();

的含義就是調(diào)用其中的函數(shù)飒硅。而且我們知道調(diào)用的函數(shù)都是類似全局變量的函數(shù)砂缩。這個之前的文章筆者有說過這里不細說了。筆者也提過這里的方法其實都是section為__mod_init_func中的數(shù)據(jù)三娩。而通過我們之前的分析也知道庵芭,__mod_init_func中的函數(shù)是先于main函數(shù)執(zhí)行的。其實在runtime庫中雀监,甚至咸魚load方法双吆,哈哈哈哈哈哈。
那這就給我們優(yōu)化App啟動提供了一個思路会前。幸好這個想法不是筆者特有好乐,有位iOS的同僚已經(jīng)做了相關(guān)工作,這里筆者就大概介紹一下他的思路瓦宜。

原文在這里:
一種 hook C++ static initializers 的方法
其想法很簡單蔚万,就是在load方法中hook__mod_init_func的方法。部分源代碼如下:

+ (void)load{
    sInitInfos = [NSMutableArray new];
    g_initializer = new std::vector<MemoryType>();
    g_cur_index = -1;
    g_aslr = 0;
    
    hookModInitFunc();
}

以及

static void hookModInitFunc(){
    Dl_info info;
    dladdr((const void *)hookModInitFunc, &info);
    
#ifndef __LP64__
    //        const struct mach_header *mhp = _dyld_get_image_header(0); // both works as below line
    const struct mach_header *mhp = (struct mach_header*)info.dli_fbase;
    unsigned long size = 0;
    MemoryType *memory = (uint32_t*)getsectiondata(mhp, "__DATA", "__mod_init_func", & size);
#else /* defined(__LP64__) */
    const struct mach_header_64 *mhp = (struct mach_header_64*)info.dli_fbase;
    unsigned long size = 0;
    MemoryType *memory = (uint64_t*)getsectiondata(mhp, "__DATA", "__mod_init_func", & size);
#endif /* defined(__LP64__) */
    for(int idx = 0; idx < size/sizeof(void*); ++idx){
        MemoryType original_ptr = memory[idx];
        g_initializer->push_back(original_ptr);
        memory[idx] = (MemoryType)myInitFunc_Initializer;
    }
    
    NSLog(@"zero mod init func : size = %@",@(size));
    
    [sInitInfos addObject:[NSString stringWithFormat:@"ASLR=%p",mhp]];
    g_aslr = (MemoryType)mhp;
}

其實大部分代碼我們都已經(jīng)可以看懂了临庇,還有疑問的讀者可以自行查閱反璃。通過這個實用工具,筆者可以輕松抓出App中啟動項的優(yōu)化空間:


優(yōu)化空間一覽

如圖所示假夺,查看func函數(shù)淮蜈,可以輕松知道其所在的文件是main.mm中。然后進入筆者的main.mm函數(shù)中發(fā)現(xiàn)聲明了一個帶構(gòu)造函數(shù)的類已卷,并引用了該類:


追蹤

于是進行優(yōu)化即可梧田。

參考

C++ 中using 的使用
https://stackoverflow.com/questions/20357106/what-does-c-expression-voidvoid0-mean

廣告

我的首款個人開發(fā)的APP壁紙寶貝上線了,歡迎大家下載悼尾。

壁紙寶貝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柿扣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子闺魏,更是在濱河造成了極大的恐慌未状,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件析桥,死亡現(xiàn)場離奇詭異司草,居然都是意外死亡艰垂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門埋虹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猜憎,“玉大人,你說我怎么就攤上這事搔课∫雀蹋” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵爬泥,是天一觀的道長柬讨。 經(jīng)常有香客問我,道長袍啡,這世上最難降的妖魔是什么踩官? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮境输,結(jié)果婚禮上蔗牡,老公的妹妹穿的比我還像新娘。我一直安慰自己嗅剖,他們只是感情好辩越,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著信粮,像睡著了一般区匣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒋院,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天亏钩,我揣著相機與錄音,去河邊找鬼欺旧。 笑死姑丑,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的辞友。 我是一名探鬼主播栅哀,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼称龙!你這毒婦竟也來了留拾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鲫尊,失蹤者是張志新(化名)和其女友劉穎痴柔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疫向,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡咳蔚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年豪嚎,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谈火。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡侈询,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糯耍,到底是詐尸還是另有隱情扔字,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布温技,位于F島的核電站啦租,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏荒揣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一焊刹、第九天 我趴在偏房一處隱蔽的房頂上張望系任。 院中可真熱鬧,春花似錦虐块、人聲如沸俩滥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霜旧。三九已至,卻和暖如春儡率,著一層夾襖步出監(jiān)牢的瞬間挂据,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工儿普, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留崎逃,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓眉孩,卻偏偏與公主長得像个绍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浪汪,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 6.11去成都找工作了巴柿,6.12去一個設(shè)計院面試,對于土木行業(yè)加上我的專業(yè)死遭,設(shè)計院現(xiàn)在是很缺人的广恢,現(xiàn)在都沒有性別限...
    cher1122閱讀 124評論 0 1
  • 秋天是落葉的季節(jié),不知不覺中樹上的葉子已經(jīng)變色呀潭,秋天的落葉是如此美袁波,像跳動的精靈瓦阐,秋天的落葉~創(chuàng)意~好玩,秋天的葉...
    笑媽Darling閱讀 488評論 0 1
  • 喜愛整理收納的姑娘們篷牌,本來今天要跟大家分享關(guān)于[整理收納]的書籍睡蟋,從整理收納的理念到技巧梳理你的整理理念。 Wha...
    嵐景閱讀 254評論 0 0
  • 陽光明媚的早上 天空湛藍 萬里無云 笨笨的你 看見了嗎枷颊? 我送了整個藍天伴你出行 聽到了嗎戳杀? 那鳥兒是我為你在歌唱...
    方想閱讀 188評論 0 0