[翻譯] 深入解析QML引擎, 第3部分: 綁定類型

原文?QML Engine Internals, Part 3: Binding Types

譯者注:這個解析QML引擎的文章共4篇瓜客,分析非常透徹隘马,在國內(nèi)幾乎沒有找到類似的分析哼绑,為了便于國內(nèi)的QT/QML愛好者和工作者也能更好的學習和理解QML引擎,故將這個系列的4篇文章翻譯過來。翻譯并不是完全直譯苔咪,有不足之處搀突,請指正刀闷,謝謝!

———————————————————————————————————————————

上一篇 綁定(Bindings)? ?下一篇 自定義解析器

這篇博文是深入解析QML引擎系列博文的第三篇仰迁。在上一篇博文中甸昏,我們揭示了QML引擎中的綁定是如何運作的。在這篇文章中徐许,我們將深入了解不同的綁定類型施蜜。某些內(nèi)容是我在開發(fā)者日對話QtQuick Under the Hood中講過的。除此之外雌隅,這篇博文中將涵蓋一些新的內(nèi)容翻默。

簡要回顧

在回顧之前缸沃,讓我們快速地瀏覽一個簡單的綁定:

圖1 綁定例子

每一個像這樣的綁定實際上是一個JavaScript函數(shù),運行時由V8引擎執(zhí)行修械。執(zhí)行的結(jié)果就是函數(shù)的返回值趾牧,然后將它設置給文本屬性。由于V8并不知道Qt對象和屬性肯污,當遇到一個對象(如parent)或一個屬性(如width)時翘单,它就請求QML中的上下文包裹類和對象包裹類去解析它們。當一個綁定被執(zhí)行時蹦渣,這些包裹類會記錄那些被訪問了的屬性哄芜,可以自動將每個屬性的改變信號(例如widthChanged())連接到一個可以重新執(zhí)行綁定的槽函數(shù)。

現(xiàn)在我們已經(jīng)重新溫習了一遍綁定的工作原理柬唯,讓我們趁熱打鐵认臊,繼續(xù)分析不同的綁定方式。

綁定方式

在上一篇文章中锄奢,我指出每一個綁定都被解析成一個QQmlBinding對象的實例失晴。這其實是一個哄騙孩子的謊言。如果每一個綁定都由QQmlBinding表示斟薇,則開銷會非常大师坎。一個典型的QML應用,即使沒有上千個綁定堪滨,至少也有成百個綁定胯陋,所以需要讓每一個綁定更加輕量級。此外袱箱,當加載一個QML文件時遏乔,每一個綁定都是單獨編譯的。因此在加載過程中會多次調(diào)用V8編譯器发笔,給系統(tǒng)造成不小的開銷盟萨。

QV8Bindings

為了解決QQmlBinding造成的開銷問題,使用了另外一個綁定類了讨,取了一個容易混淆的名字:QV8Bindings捻激。QV8Bindings內(nèi)部用了一個數(shù)組來存放QML文件中的所有綁定,綁定用更加輕量級的QV8Bindings::Binding結(jié)構體來表示前计。QML的開發(fā)者過去花了很大力氣去減少這種結(jié)構的內(nèi)存占用胞谭,他們甚至發(fā)現(xiàn)指針的最后兩位因為對齊的關系而沒有被使用。然后喪心病狂地利用這些空間去保存標志位男杈,最終做到一個QV8Bindings::Binding只占用了64個字節(jié)丈屹。

QV8Bindings和QQmlBinding相比,有一個大優(yōu)勢是伶棒,所有綁定都是在一起編譯的旺垒,所以只需要調(diào)用一次V8編譯器彩库。在QQmlCompiler ::completeComponentBuild()函數(shù)中,你會發(fā)現(xiàn)先蒋,在編譯QML文件時骇钦,所有的綁定函數(shù)會組成一個大的JavaScript程序,并存儲在QQmlCompiledData(用于包含QML文件中所有類型的編譯數(shù)據(jù))竞漾。當QML文件第一次實例化時司忱,QV8Bindings::QV8Bindings()將對綁定程序進行編譯,編譯后保存在QQmlCompiledData中畴蹭,然后將源代碼丟棄。當再次實例化相同的QML文件時鳍烁,QML引擎將直接使用QQmlCompiledData中已編譯的綁定程序叨襟,并不需要再編譯一次它們。然而QQmlBinding卻不是這樣幔荒,每次實例化QML文件都需要執(zhí)行一次編譯糊闽。

小結(jié):因為QV8Bindings把QML文件中所有的綁定組織在一起,所以可以花費更少的內(nèi)存爹梁,并只執(zhí)行一次編譯右犹。

那為什么我們不拋棄QQmlBinding?這個類為什么還依舊存在呢姚垃?某些情況下念链,綁定是不可共享的,例如它們使用了閉包或者使用了eval()函數(shù)积糯。在這種情況下掂墓,每個綁定函數(shù)需要不同的上下文。因此不能和具有相同上下文的其他綁定一起編譯看成。因此在這種特殊情況下君编,將會使用QQmlBinding來表示綁定。當編譯一個QML文件時川慌,是由QQmlCompiler::completeComponentBuild()來判定采用哪種綁定方式吃嘿。另外,SharedBindingTester會檢測綁定應該用QV8Bindings梦重,還是QQmlBinding兑燥。SharedBindingTester就是一個JS AST的訪問者。如果你查看一下代碼忍饰,你會發(fā)現(xiàn)SharedBindingTester也會測試哪些綁定是安全的贪嫂,同時在QML文件初始化時避免多次執(zhí)行綁定,源代碼的提交信息做了最好的描述艾蓝。

為了讓QML代碼更加的簡潔力崇,QQmlBinding和QV8Bindings::Binding都從QQmlAbstractBinding繼承斗塘。

QV4Bindings

假如你看過一些QML引擎的代碼,你很可能已注意到QV4Bindings類亮靴,這個類也是QQmlAbstractBinding的子類馍盟。它是另一個綁定類型嗎?和什么有關呢?與QV8Bindings相同的是,它也是QML文件中所有綁定的集合茧吊。不同的是贞岭,QV4Bindings只保存所謂優(yōu)化過的綁定,也有人錯誤和混淆地稱之為編譯過的綁定搓侄。有一些綁定是可以被優(yōu)化的瞄桨,它們會用QV4Bindings表示,有一些綁定不能被優(yōu)化讶踪,它們會用QV8Bindings來表示芯侥。

那么這個優(yōu)化是什么呢?QV4Bindings并不由V8引擎執(zhí)行乳讥,它會被編譯成字節(jié)碼柱查,通過一個字節(jié)碼解析器執(zhí)行。這個字節(jié)碼編譯器和解析器無法處理所有的JavaScript表達式,因為不可能提前編譯所有的JavaScript云石。

但是為什么使用字節(jié)碼呢唉工?V8引擎會編譯成機器碼,難道不比一個字節(jié)碼解析器快嗎汹忠?結(jié)果證明它真的沒有字節(jié)碼解析器快淋硝,V8引擎執(zhí)行綁定時,需要調(diào)用QML來解析對象和屬性错维,這個處理需要很大的開銷奖地。另外當一個函數(shù)被多次調(diào)用時,V8引擎可能會在比較繁忙的情況下重新編譯一個函數(shù)赋焕,以此做更多地優(yōu)化参歹。對于QML的情況而言,所有這些處理都會造成很大的開銷隆判,因為QML通常包含很多只有一句代碼的綁定犬庇。這里有一個我為開發(fā)者日準備的基準測試結(jié)果。在測試中侨嘀,我只是簡單的讓QML引擎執(zhí)行一個綁定幾百次臭挽。這是一個可以讓V4引擎輕松處理的簡單綁定。為了和V8引擎比較咬腕,設置環(huán)境變量QML_DISABLE_OPTIMIZER=1來完全禁用V4綁定欢峰。

圖2 V4和V8綁定執(zhí)行效率對比

如你所見,在這種特定情形下,V4字節(jié)碼引擎的確比V8快多了纽帖。

從本質(zhì)上說宠漩,V4就是一個寄存器機器。和CPU相同的是懊直,它具有的寄存器扒吁,用來存儲臨時值。不同的是室囊,它不會從內(nèi)存加載和儲存值——它從類的屬性加載和儲存值雕崩。設置環(huán)境變量QML_BINDINGS_DUMP=1,讓我們看一個簡單的綁定:

圖3 簡單綁定例子

其指令輸出是:

圖4 綁定執(zhí)行指令

如你所見融撞,屬性width和height被加載到寄存器0和1中盼铁,然后這些寄存器乘起來,把結(jié)果保存在文本屬性中(文本屬性在QQuickText類中的屬性編號是42)尝偎。FetchAndSubscribe指令不僅加載屬性捉貌,也會監(jiān)聽它的改變信號,從而實現(xiàn)綁定的自動更新冬念。從上文的"匯編"代碼中,你還可以發(fā)現(xiàn)另一個優(yōu)勢:V4編譯器是在編譯時解析對象和屬性牧挣,并將屬性的索引保存在字節(jié)碼中急前。所以在運行時,就可以直接通過索引訪問屬性瀑构,不用通過屬性名字進行查找裆针。而V8引擎則需要調(diào)用QML對象和上下文包裝器來解析對象和屬性,這當然會產(chǎn)生更多的開銷寺晌。但是缺點是世吨,V4引擎無法處理動態(tài)對象,例如那些通過setContextProperty()從C++導出的對象呻征。如果綁定中含這種動態(tài)對象耘婚,則需要使用QV8Binding。

總結(jié)

歸納起來陆赋,有3個綁定類型沐祷,都是從QQmlAbstractBinding繼承:

1. QV4Bindings::Binding

2. QV8Bindings::Binding

3. QQmlBinding

QV4Bindings是最快的,因為其使用了自定義的字節(jié)碼引擎攒岛。QV8Bindings和QQmlBinding都是使用V8 JS引擎執(zhí)行赖临,但QV8Bindings將所有的綁定組織在一起,一次性編譯灾锯,然而QQmlBindings會在每個QML組件實例化過程中一個一個地進行編譯兢榨。

這有一個展示所有綁定類型的(沒啥用的)例子:

圖5 三種類型的綁定的例子

設置環(huán)境變量QML_COMPILER_DUMP=1,你會看到QML編譯器使用了兩次STORE_COMPILED_BINDING,一次STORE_V8_BINDING和一次STORE_BINDING吵聪。

STORE_BINDING為QQmlBinding凌那,它用于font.pointSize,因為綁定使用了eval()暖璧,因此不可以被共享案怯。

anchors.centerIn的綁定和文字都是V4綁定(STORE_COMPILED_BINDING指令,QV4Bindings:: Binding類)澎办。

最后嘲碱,font.wordSpacing是一個普通的QV8Bindings::Binding(STORE_V8_BINDING指令)。V4的字節(jié)碼編譯器和解析器應對三元運算符完全沒有問題局蚀,但是求補運算尚未實現(xiàn)麦锯,所以QML編譯器選擇使用V8綁定。

在這個系列的下一篇博文中琅绅,我們將嘗試自定義解析器扶欣。如果有什么疑問或者對QML應用和研究感興趣的朋友裸违,歡迎加入我們進行討論(QQ群:280689979)唠雕。如需轉(zhuǎn)載,無須我們授權权均,但需要注明原文鏈接(該文的鏈接)澎羞,及原作者髓绽,謝謝!

上一篇 綁定(Bindings)? 下一篇 自定義解析器

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末妆绞,一起剝皮案震驚了整個濱河市顺呕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌括饶,老刑警劉巖株茶,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異图焰,居然都是意外死亡启盛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門技羔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驰徊,“玉大人,你說我怎么就攤上這事堕阔」鞒В” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵超陆,是天一觀的道長牺弹。 經(jīng)常有香客問我浦马,道長,這世上最難降的妖魔是什么张漂? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任晶默,我火速辦了婚禮,結(jié)果婚禮上航攒,老公的妹妹穿的比我還像新娘磺陡。我一直安慰自己,他們只是感情好漠畜,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布币他。 她就那樣靜靜地躺著,像睡著了一般憔狞。 火紅的嫁衣襯著肌膚如雪蝴悉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天瘾敢,我揣著相機與錄音拍冠,去河邊找鬼。 笑死簇抵,一個胖子當著我的面吹牛庆杜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碟摆,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼欣福,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了焦履?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤雏逾,失蹤者是張志新(化名)和其女友劉穎嘉裤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栖博,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡屑宠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了仇让。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片典奉。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖丧叽,靈堂內(nèi)的尸體忽然破棺而出卫玖,到底是詐尸還是另有隱情,我是刑警寧澤踊淳,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布假瞬,位于F島的核電站陕靠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏脱茉。R本人自食惡果不足惜剪芥,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琴许。 院中可真熱鬧税肪,春花似錦、人聲如沸榜田。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽串慰。三九已至偏塞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邦鲫,已是汗流浹背灸叼。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留庆捺,地道東北人古今。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像滔以,于是被迫代替她去往敵國和親捉腥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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