歡迎光臨
每天分享高質量文章

從V8 JS引擎學到的優化經驗

V8是谷歌開源的一個高性能JavaScript引擎,用 C++ 實現,並用在谷歌的開源瀏覽器Chrome里。

為什麼V8非常快,哪種方案讓V8達到這種速度?發現其中秘密是一件有趣的事情。

面向物件、設計樣式與性能

有些C/C++開發者有些奇怪的觀念。他們認為使用面向物件和設計樣式會降低程式的性能。但V8證明瞭這種觀念是錯誤的。V8的實現使用了許多設計樣式,但依然非常高效。

下麵列出V8中使用的兩個樣式:

工廠樣式

當Javascript引擎執行一個腳本時,引擎為遇到的每個變數、函式或陣列都創建一個實體。JSObject是所有這些物件的父物件。

下麵列出了所有繼承自JSObject的類:

V8實現了一個工廠類來創建這些物件,該類中的Factory::NewJsObject就是用來創建這些物件的。

下麵列出了所有使用該類/方法的方法。

V8引擎中的類並沒有直接使用這個工廠類,而是添加了另一層封裝,通過Heap類呼叫該工廠類。

訪問者樣式:

維基百科上這樣解釋觀察者樣式:

觀察者設計樣式是將演算法和演算法處理的物件分開的一種方式。這種分離可以在不修改結構本身的情況下,將新的操作添加到已有的物件結構上。這是一條遵循open/closed準則的方式。

與工廠樣式相似,訪問者樣式也為實現添加了封裝層。這樣讓其代碼更加可讀且可維護。

V8原始碼中許多類都實現了訪問者樣式。

即使V8開發者必須優化執行效率,他們也不在乎添加到代碼中的封裝層。使用設計樣式和添加一些C++的機制會增加一些封裝,所以的確會對效率有影響。但這對效率的影響僅占一小部分,更多的影響來自該應用使用的設計決策。

V8中針對執行效率方面的設計決策

1. 隱藏類和快速屬性訪問。

JavaScript是一種動態編程語言:可以在物件運行時為物件添加或刪除熟悉。這意味著很容易改變物件的屬性。

JSFunction和JSValue的父類都是JSObject,JSFunction用來表示一個javascript函式,JSValue用來表示一個javascript值。但沒有繼承自JSObject的類,用以表示Function或Value這樣的Class。許多JavaScript引擎使用詞典型別的資料結構來儲存這些物件的熟悉,訪問每個屬性都需要動態查找並解析屬性在記憶體中的位置。

這種方式導致JavaScript在訪問物件變數的屬性時,比在Java或Smalltalk中要慢。在這些語言中,實列變數分配的位置是固定的,即由編譯器根據物件的類定義中的佈局,在該物件在記憶體中的位置加上固定的偏移位置。因此訪問這些屬性僅僅是記憶體上的讀取或儲存,而這種操作通常只需一條指令。

V8使用隱藏類概念來降低訪問JavaScript屬性所消耗的時間。V8不使用動態查詢來訪問屬性,而是在幕後創建隱藏類。

2. 動態生產機器碼

在首次執行時,V8就將JavaScript原始碼直接編譯成機器碼,沒有中間位元組碼,沒有解釋器。屬性訪問由行內的快取代碼處理,V8執行時可能會有其他機器指令修改這些快取代碼。

3. 高效的垃圾收集器

在執行過程中,V8會重新獲得廢棄物件的記憶體,即垃圾回收。為了保證擁有較快的物件分類、較短的垃圾回收停頓,以及沒有記憶體碎片。V8使用了停頓、分代、精確垃圾回收器。這意味著V8使用了:

  • 在垃圾回收迴圈期間停止程式的執行。

  • 在大多數垃圾迴圈中,只處理物件堆的一部分。這最大化降低了停頓對應用的影響。

  • 記錄所有物件和指標在記憶體中的位置,避免了將物件作為指標識別而導致的記憶體泄漏。

結論:

出於效率因素而不使用面向物件或設計樣式,這是一個錯誤的觀念。這樣只會獲得數毫秒的優化,卻失去了代碼的可讀性和可維護性。

原文出處:www.codergears.com

譯文出處:伯樂在線 – Daetalus

赞(0)

分享創造快樂