Swift Runtime 編譯和運(yùn)行時(shí)原理初探

14年Swift推出時(shí)的主打口號就是“快”。這也十分高調(diào)地被體現(xiàn)在這門語言的名字上了道逗。其實(shí)快字主要體現(xiàn)在編譯器運(yùn)行時(shí)系統(tǒng)拇舀。新的Swift編譯器更智能变抽,能夠識別對象和方法的調(diào)用關(guān)系以及層級關(guān)系奔缠,減少對象調(diào)用方法的查找時(shí)間掠抬;同時(shí)在內(nèi)存管理上也有所提高。

首先簡要回顧一下ObjC runtime的原理校哎,ObjC使用Messaging策略——選擇器向接收器發(fā)送消息两波,編譯階段無法得知接收器對象或類是否有對應(yīng)的方法,僅將自定義的面向?qū)ο箢愋途幾g生成對應(yīng)的運(yùn)行時(shí)類型闷哆,即大量C結(jié)構(gòu)體和C函數(shù)腰奋。程序運(yùn)行時(shí)階段,運(yùn)行時(shí)系統(tǒng)根據(jù)對象的isa指針找到對象所屬的類結(jié)構(gòu)體抱怔,然后通過結(jié)合類中的緩存方法列表指針和虛函數(shù)表指針進(jìn)行查找選擇器對應(yīng)的SEL選擇器類型變量劣坊,如果找到則根據(jù)SEL變量對應(yīng)的IMP指針找到方法實(shí)現(xiàn)。若找不到對應(yīng)的方法野蝇,則會啟動(dòng)消息轉(zhuǎn)發(fā)機(jī)制讼稚,如果仍然失敗括儒,則拋出運(yùn)行時(shí)異常绕沈。

這個(gè)Messaging的過程是ObjC runtime消耗資源的一大因素。而大部分的方法調(diào)用帮寻,尤其是重復(fù)的方法調(diào)用乍狐,并沒有必要次次都從頭開始進(jìn)行查找,消息分發(fā)固逗、轉(zhuǎn)發(fā)浅蚪。而Swift一定程度上減少了這種重復(fù)的勞動(dòng)。

當(dāng)Swift的運(yùn)行時(shí)的一個(gè)對象在調(diào)用方法時(shí)烫罩,編譯器會使用類似C++的虛表("vtable")來查找方法實(shí)現(xiàn)惜傲。vtable是組成Swift類的一個(gè)存儲該類所有方法的函數(shù)指針的數(shù)組,運(yùn)行時(shí)可以簡單地通過下標(biāo)訪問這些函數(shù)指針贝攒。于是當(dāng)你的自定義代碼第一次調(diào)用方法:

object.myMethod()

編譯器大概會執(zhí)行如下的偽代碼:

methodImplementation = object->class.vtable[indexOfMyMethod];

methodImplementation();

可以看出簡單地使用數(shù)組下標(biāo)訪問函數(shù)指針來獲取方法實(shí)現(xiàn)代碼會比消息分發(fā)的若干步驟要快捷一些盗誊。如果你的Swift方法聲明是一個(gè)final關(guān)鍵字修飾過的:

@final func myMethod() { //lots of implementation code here }

那對其進(jìn)行查找會更快,因?yàn)镾wift編譯器會直接訪問該方法實(shí)現(xiàn)的地址,這就無需運(yùn)行時(shí)再去查找哈踱,完全繼承使用了靜態(tài)語言的優(yōu)勢荒适。

現(xiàn)在如果把上面的方法中的實(shí)現(xiàn)代碼刪除,變成一個(gè)空方法:

@final func myMethod() { //nothing here, blank }

然后再去嘗試調(diào)用這個(gè)方法开镣,Swift編譯器可以第一時(shí)間發(fā)現(xiàn)這個(gè)方法沒有實(shí)現(xiàn)代碼刀诬,即使你寫了相應(yīng)的調(diào)用代碼,編譯器也完全不會理會邪财,直接在完成了方法的前一句編譯就結(jié)束陕壹。

通常情況下如果將某個(gè)類的實(shí)例作為方法入口參數(shù)進(jìn)行傳遞,編譯器只能夠判斷這個(gè)參數(shù)的類型要么是這個(gè)類卧蜓,要么是這個(gè)類的子類帐要。因此在方法調(diào)用的時(shí)候,Swift運(yùn)行時(shí)會對這個(gè)類及其子類的vtable進(jìn)行查找弥奸。但如果在實(shí)例進(jìn)行初始化時(shí)明確了類型榨惠,編譯階段便清楚調(diào)用的方法在哪個(gè)類中,則在運(yùn)行時(shí)調(diào)用時(shí)會直接跳轉(zhuǎn)到該方法的實(shí)現(xiàn)代碼中去盛霎,省去了動(dòng)態(tài)查找的步驟赠橙。

以上是Swift的編譯器和運(yùn)行時(shí)系統(tǒng)對方法調(diào)用的一些優(yōu)化,此外對于內(nèi)存管理愤炸,Swift除了徹底拋棄MRC使用ARC外期揪,還對對象的生命周期進(jìn)行了一定的優(yōu)化。

比如你使用了一個(gè)循環(huán)规个,循環(huán)次數(shù)是一百萬次凤薛,循環(huán)內(nèi)會創(chuàng)建一個(gè)局部的類實(shí)例,同時(shí)發(fā)送一個(gè)消息給實(shí)例對象:

for _ in 0...1000000?{ obj.myMethod() }

這在ObjC中诞仓,選擇器發(fā)送消息的次數(shù)也會達(dá)到一百萬次缤苫。這在Swift中會有極大的不同,并且可以分成幾種情況:

第一種情況墅拭,如果myMethod的方法體中沒有方法實(shí)現(xiàn)代碼活玲,是空函數(shù),則Swift根本不會進(jìn)入循環(huán)執(zhí)行方法谍婉,而是直接跳過這個(gè)循環(huán)執(zhí)行下面的代碼舒憾;

第二種情況,如果方法體中有方法穗熬,同時(shí)這個(gè)obj對象自創(chuàng)建以來除了調(diào)用過myMethod方法外镀迂,并沒有被其他變量或方法使用,同時(shí)obj僅僅是在外部的函數(shù)體的花括號內(nèi)被作為局部變量創(chuàng)建和釋放唤蔗,而且myMethod的作用范圍也不超過obj創(chuàng)建和釋放的范圍探遵。在ObjC的編譯運(yùn)行時(shí)環(huán)境下唧瘾,obj依然會被發(fā)送一百萬次重復(fù)的消息。

但是别凤,在Swift編譯環(huán)境下饰序,編譯器擁有足夠的信息能夠推斷出這個(gè)obj對象只會在創(chuàng)建和釋放之間進(jìn)行一百萬次的方法調(diào)用這個(gè)結(jié)論后,編譯器不會分配堆內(nèi)存給obj進(jìn)行初始化规哪。相反的求豫,編譯器會將obj創(chuàng)建在棧上。這樣诉稍,作為一個(gè)局部變量蝠嘉,生來僅僅是為調(diào)用myMethod()一百萬次,在棧上被分配內(nèi)存顯然會比在堆中更快更合理杯巨。

此外蚤告,Swift還有對寄存器存取方法參數(shù)選擇上的優(yōu)化,把本會使用寄存器來存取的ObjC的方法中默認(rèn)隱式參數(shù)self和_cmd中的_cmd去掉服爷,相當(dāng)于增加了一個(gè)給自定義入口參數(shù)的使用比棧內(nèi)存更快的寄存器存取的指標(biāo)杜恰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仍源,隨后出現(xiàn)的幾起案子心褐,更是在濱河造成了極大的恐慌,老刑警劉巖笼踩,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逗爹,死亡現(xiàn)場離奇詭異,居然都是意外死亡嚎于,警方通過查閱死者的電腦和手機(jī)掘而,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來于购,“玉大人袍睡,你說我怎么就攤上這事〖劾裕” “怎么了女蜈?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵持舆,是天一觀的道長色瘩。 經(jīng)常有香客問我,道長逸寓,這世上最難降的妖魔是什么居兆? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮竹伸,結(jié)果婚禮上泥栖,老公的妹妹穿的比我還像新娘簇宽。我一直安慰自己,他們只是感情好吧享,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布魏割。 她就那樣靜靜地躺著,像睡著了一般钢颂。 火紅的嫁衣襯著肌膚如雪钞它。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天殊鞭,我揣著相機(jī)與錄音遭垛,去河邊找鬼。 笑死操灿,一個(gè)胖子當(dāng)著我的面吹牛锯仪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播趾盐,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼庶喜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了救鲤?” 一聲冷哼從身側(cè)響起溃卡,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜒简,沒想到半個(gè)月后瘸羡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡搓茬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年犹赖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卷仑。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡峻村,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锡凝,到底是詐尸還是另有隱情粘昨,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布窜锯,位于F島的核電站张肾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏锚扎。R本人自食惡果不足惜吞瞪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望驾孔。 院中可真熱鬧芍秆,春花似錦惯疙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荆虱,卻和暖如春掉分,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背克伊。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工酥郭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人愿吹。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓不从,卻偏偏與公主長得像,于是被迫代替她去往敵國和親犁跪。 傳聞我的和親對象是個(gè)殘疾皇子椿息,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

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