摘要:是開發(fā)的引擎它是開源的,而且是用編寫的。本文的目的是展示和理解如何工作,以便為客戶端或服務器端應用程序生成優(yōu)化的代碼。將如何處理這種情況事實上,每當構(gòu)造函數(shù)聲明一個屬性并跟蹤隱藏類的變化時,就會創(chuàng)建一個新的隱藏類。
V8是google開發(fā)的JavaScript引擎, 它是開源的 ,而且是用C++編寫的。它是用于客戶端(Google Chrome)和服務器端(node.js)JavaScript應用程序。
V8最初旨在提高Web瀏覽器中JavaScript執(zhí)行的性能。為了提升速度,V8將JavaScript代碼轉(zhuǎn)換為更高效的機器語言,而不是使用解釋器。它通過實現(xiàn) JIT(即時編譯器)將JavaScript代碼編譯成機器代碼,就像許多現(xiàn)代JavaScript引擎(如SpiderMonkey或Rhino(Mozilla))所做的那樣。與V8的主要區(qū)別在于它不會產(chǎn)生字節(jié)碼或任何中間代碼。
本文的目的是展示和理解 V8如何工作,以便為客戶端或服務器端應用程序生成優(yōu)化的代碼。如果您已經(jīng)在問自己“我應該關(guān)心JavaScript性能嗎?”那么我將回答Daniel Clifford(技術(shù)主管和V8團隊經(jīng)理)的一句話:“這不僅僅是讓您當前的應用程序運行得更快,而是關(guān)于實現(xiàn)你過去從未做過的事情“。
隱藏的classJavaScript是一種基于原型的語言:no classes,并且使用克隆過程創(chuàng)建對象(原型鏈)。JavaScript也是動態(tài)類型的:類型和類型信息不是顯式的,屬性可以動態(tài)添加到對象中或從中刪除。有效訪問類型和屬性是V8的首要挑戰(zhàn)。而不是使用類似字典的數(shù)據(jù)結(jié)構(gòu)來存儲對象屬性和進行動態(tài)查找來解析屬性位置(就像大多數(shù)JavaScript引擎一樣),V8在運行時創(chuàng)建隱藏類,以便具有內(nèi)部表示類型系統(tǒng)和改善屬性訪問時間。
讓我們有一個Point函數(shù)和兩個Point對象的創(chuàng)建:
https://p1.ssl.qhimg.com/t016...
如果布局相同(這里是這種情況),則p和q屬于由V8創(chuàng)建的相同隱藏類。這突出了使用隱藏類的另一個優(yōu)點:它允許V8對屬性相同的對象進行分組。這里p和q有一定的代碼優(yōu)化。
現(xiàn)在,讓我們假設我們想在我們的q對象之后添加一個z屬性,就在它聲明之后(對于動態(tài)類型語言來說這是完全沒問題的)。
V8將如何處理這種情況?事實上,每當構(gòu)造函數(shù)聲明一個屬性并跟蹤隱藏類的變化時,V8 就會創(chuàng)建一個新的隱藏類。為什么?因為如果創(chuàng)建了兩個對象(p和q)并且在創(chuàng)建后將成員添加到第二個對象(q),則V8需要保留最后創(chuàng)建的隱藏類(對于第一個對象p)并創(chuàng)建一個新對象(對于第二個對象q)與新成員。
https://p4.ssl.qhimg.com/t01c...
每次創(chuàng)建一個新的隱藏類時,前一個隱藏類都會更新一個類轉(zhuǎn)換,指示必須使用哪個隱藏類。
因此:
初始化構(gòu)造函數(shù)中的所有對象成員(因此實例稍后不會更改類型)
始終以相同的順序初始化對象成員
代碼優(yōu)化因為V8為每個屬性創(chuàng)建一個新的隱藏類,所以應該將隱藏的類創(chuàng)建保持在最低限度。為此,請盡量避免在創(chuàng)建對象后添加屬性,并始終以相同的順序初始化對象成員(以避免創(chuàng)建不同的隱藏類樹)。
[Update ]另一個技巧:單態(tài)操作是僅對具有相同隱藏類的對象起作用的操作。當我們調(diào)用一個函數(shù)時,V8會創(chuàng)建一個隱藏類。如果我們用不同的參數(shù)類型再次調(diào)用它,V8需要創(chuàng)建另一個隱藏類:首選單態(tài)代碼到多態(tài)代碼
有關(guān)V8如何優(yōu)化JavaScript代碼的更多示例 標記值為了有效地表示數(shù)字和JavaScript對象,V8表示具有 32位值。它使用一個位來知道它是一個對象(flag = 1)還是一個整數(shù)(flag = 0),這里稱為SMall Integer或 SMI ,因為它的31位。然后,如果數(shù)值大于31位,則V8將對該數(shù)字進行選擇,將其變?yōu)殡p精度并創(chuàng)建一個新對象以將數(shù)字放入其中。
代碼優(yōu)化:盡可能使用31位帶符號數(shù)字,以避免對JavaScript對象進行消耗性能的封裝操作。
數(shù)組V8使用兩種不同的方法來處理數(shù)組:
快速元素:專為那些鍵組非常緊湊的陣列而設計。它們具有線性存儲緩沖區(qū),可以非常有效地訪問它。
字典元素:專為稀疏數(shù)組而設計,它們內(nèi)部沒有所有元素。它實際上是一個哈希表,它的性能消耗比“快速元素”更昂貴。
代碼優(yōu)化:確保V8使用“快速元素”來處理數(shù)組,換句話說,避免使用稀疏數(shù)組。另外,盡量避免預先分配大型數(shù)組。最后,不要刪除數(shù)組中的元素:它使鍵集稀疏。
a = new Array(); for (var b = 0; b < 10; b++) { a[0] |= b; // Oh no! } //vs. a = new Array(); a[0] = 0; for (var b = 0; b < 10; b++) { a[0] |= b; // Much better! 2x faster. }
此外,雙精度陣列更快 - 數(shù)組的隱藏類跟蹤元素類型,并且僅包含雙精度的數(shù)組是未裝箱的(這會導致隱藏的類更改)。但是,由于裝箱和拆箱,粗心操作陣列會導致額外的工作 - 例如
var a = new Array(); a[0] = 77; // Allocates a[1] = 88; a[2] = 0.5; // Allocates, converts a[3] = true; // Allocates, converts
效率低于:
var a = [77, 88, 0.5, true];V8如何編譯JavaScript代碼? V8有兩個編譯器!
一個“完整”編譯器,可以為任何JavaScript生成良好的代碼。此編譯器的目標是快速生成代碼。為了實現(xiàn)其目標,它不進行任何類型分析,也不了解類型。相反,它使用內(nèi)聯(lián)緩存或“IC”策略來在程序運行時優(yōu)化有關(guān)類型的知識。IC效率非常高,速度可提高20倍。
優(yōu)化編譯器,可為大多數(shù)JavaScript語言生成出色的代碼。它稍后會重新編譯熱門功能。優(yōu)化編譯器從內(nèi)聯(lián)緩存中獲取類型,并決定如何更好地優(yōu)化代碼。但是,某些語言功能尚不支持,例如try / catch塊。(try / catch塊的解決方法是在函數(shù)中編寫“非穩(wěn)定”代碼并在try塊中調(diào)用函數(shù))
代碼優(yōu)化:V8還支持去優(yōu)化:優(yōu)化編譯器從內(nèi)聯(lián)緩存中對不同類型做出假設,如果這些假設無效則會進行去優(yōu)化。例如,如果生成的隱藏類不是預期的類,則V8會拋棄優(yōu)化的代碼并返回到完整編譯器以從內(nèi)聯(lián)緩存中再次獲取類型。此過程很慢,應該通過在優(yōu)化后嘗試不更改功能來避免。
資源
谷歌I / O 2012“與V8打破JavaScript速度限制”,V8團隊的技術(shù)主管兼經(jīng)理Daniel Clifford:視頻和幻燈片。
V8:一個開源JavaScript引擎:Lars Bak,V8核心工程師的視頻。
Nikkei Electronics Asia博客文章:為什么新的谷歌V8引擎如此之快?
博客評論由Disqus提供
譯者注:
關(guān)于本文中提到的一些知識點,做一些簡單的只是擴展,希望對你們理解本文有一些幫助;
1、 "JavaScript has no classes"
雖然JavaScript是面向?qū)ο蟮恼Z言,但它不是基于類的語言 - 它是基于原型的語言。
在js和java或其他“基于類”的編程語言中類的工作方式之間存在一些深刻的差異。
相關(guān)討論
2、快速元素和字典元素
快速或字典元素:元素的第二個主要區(qū)別是它們是快速還是字典模式。快速元素是簡單的VM內(nèi)部數(shù)組,其中屬性索引映射到元素存儲中的索引。但是,這種簡單的表示對于非常大的稀疏/多孔數(shù)組而言是相當浪費的,其中只占用很少的條目。在這種情況下,我們使用基于字典的表示來節(jié)省內(nèi)存,但代價是訪問速度稍慢:
const sparseArray = []; sparseArray[9999] = "foo"; // Creates an array with dictionary elements. sparseArray.length // 10000 sparseArray[0] // undefined
在這個例子中,分配一個包含10k條目的完整數(shù)組會相當浪費。相反,V8會創(chuàng)建一個字典來存儲鍵值描述符三元組。在這種情況下,密鑰是"9999",并且使用值"foo"和默認描述符。鑒于我們沒有辦法在HiddenClass上存儲描述符詳細信息,只要您使用自定義描述符定義索引屬性,V8就會轉(zhuǎn)向減慢元素:
const array = []; Object.defineProperty(array, 0, {value: "fixed" configurable: false}); console.log(array[0]); // Prints "fixed". array[0] = "other value"; // Cannot override index 0. console.log(array[0]); // Still prints "fixed".
引用文檔
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/99149.html
摘要:本章將會深入谷歌引擎的內(nèi)部結(jié)構(gòu)。一個引擎可以用標準解釋程序或者即時編譯器來實現(xiàn),即時編譯器即以某種形式把解釋為字節(jié)碼。引擎的由來引擎是由谷歌開源并以語言編寫。注意到?jīng)]有使用中間字節(jié)碼來表示,這樣就不需要解釋器了。 原文請查閱這里,略有刪減。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第二章。 本章將會深入谷歌 V8 引擎的內(nèi)部結(jié)構(gòu)。我們也會...
摘要:第二篇文章將深入谷歌的引擎的內(nèi)部。引擎可以實現(xiàn)為標準解釋器,或者以某種形式將編譯為字節(jié)碼的即時編譯器。這個引擎是在谷歌中使用的,但是,與其他引擎不同的是也用于流行的。一種更復雜的優(yōu)化編譯器,生成高度優(yōu)化的代碼。不是唯一能夠做到的引擎。 本系列的 第一篇文章 主要介紹引擎、運行時和調(diào)用堆棧。第二篇文章將深入谷歌 V8 的JavaScript引擎的內(nèi)部。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHu...
摘要:第二篇文章將深入谷歌的引擎的內(nèi)部。引擎可以實現(xiàn)為標準解釋器,或者以某種形式將編譯為字節(jié)碼的即時編譯器。這個引擎是在谷歌中使用的,但是,與其他引擎不同的是也用于流行的。一種更復雜的優(yōu)化編譯器,生成高度優(yōu)化的代碼。不是唯一能夠做到的引擎。 本系列的 第一篇文章 主要介紹引擎、運行時和調(diào)用堆棧。第二篇文章將深入谷歌 V8 的JavaScript引擎的內(nèi)部。 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHu...
摘要:引擎可以是一個標準的解釋器,也可以是一個將編譯成某種形式的字節(jié)碼的即時編譯器。和其他引擎最主要的差別在于,不會生成任何字節(jié)碼或是中間代碼。不使用中間字節(jié)碼的表示方式,就沒有必要用解釋器了。 原文地址:https://blog.sessionstack.com... showImg(https://segmentfault.com/img/bVVwZ8?w=395&h=395); 數(shù)周之...
摘要:摘要性能彪悍的引擎。深入淺出系列深入淺出第課箭頭函數(shù)中的究竟是什么鬼深入淺出第課函數(shù)是一等公民是什么意思呢深入淺出第課什么是垃圾回收算法深入淺出第課是如何工作的最近,生態(tài)系統(tǒng)又多了個非常硬核的項目。 摘要: 性能彪悍的V8引擎。 《JavaScript深入淺出》系列: JavaScript深入淺出第1課:箭頭函數(shù)中的this究竟是什么鬼? JavaScript深入淺出第2課:函數(shù)是一...
閱讀 3735·2023-01-11 11:02
閱讀 4244·2023-01-11 11:02
閱讀 3050·2023-01-11 11:02
閱讀 5180·2023-01-11 11:02
閱讀 4737·2023-01-11 11:02
閱讀 5534·2023-01-11 11:02
閱讀 5313·2023-01-11 11:02
閱讀 3990·2023-01-11 11:02