1. 程式人生 > >新版V8引擎的一些介紹和了解

新版V8引擎的一些介紹和了解

2017年的谷歌I/O大會召開。本文主要介紹在這次I/O大會上關於V8引擎最新的一些東西。

效能優化的多方權衡

在最開始,介紹一些關於瀏覽器引擎優化的基本路線,看看對瀏覽器引擎優化一般從哪幾個方面著手。V8雖然在對javascript優化上取得很大的進步,將js的速度相比與最初提升了數十倍,採取了諸如隱藏類加PICs的技術加速屬性讀取,JIT技術等,但仍然存在一些問題。下面是主要幾個

  • 一般來說,優化程度越好,產生機器程式碼的速度越快, 但會造成程式的初始化時間加長
  • 高度優化技術會造成很高的記憶體佔用
    所以,在優化編譯程式碼的時候需要在這幾個方面進行權衡。下面這張圖可以表示這中權衡過程。
    這裡寫圖片描述

我們在上面提到過,優化程度的好壞影響著機器程式碼產生的快慢,優化越好,自然程式碼執行的速度會更快,但是會造成更長的初始化延遲,因為所有這些優化,發生在載入頁面後面,瀏覽器首次遇到js程式碼的時候。所以第一個權衡就是程式啟動時候的延遲和它啟動後能達到的最高效能。而第二個權衡就是在JIT中,若要採取越多的優化,那麼同時會佔用更多的記憶體。所以,引擎在執行某個函式的時候需要考慮要更快的啟動還是更快的執行,更低的記憶體還是更好的優化。

下面我們先來看看不同情況下的權衡需求。

foo(2)

現在這裡有個頁面,裡面只包含一個foo函式,並且不知道它實際做什麼。我們會發現js直譯器本身的執行速度會比帶有優化的js compiler速度快很多(雖然潛意識裡你會認為直譯器要慢的多)。因為當compiler遇到這個函式的時候,會把它轉換成原生程式碼並且經過多次優化處理,而這一切會發生在執行之前。所以當你只需執行一次foo函式的時候,權衡策略應該這樣:
這裡寫圖片描述


這時候可能會以fast stratup為主,因為peak performance主要針對的是多次執行。
再看下面這種情況。

for(let i = 0;i<1E4;i++){
    foo(i)
}

這裡的程式碼會執行foo函式10000次,我們會延長初始化時間來得到儘可能多的優化,並且轉換成原生程式碼。而優化所用的時間可以均攤到10000次執行過程中。那麼在這種情況下,將採取這種均衡策略:
這裡寫圖片描述
我們會花費更多的初始化時間和更多的記憶體來大大提高多次執行時速度。當然,在桌面瀏覽器上完成這些優化工作是沒有問題的,因為它有足夠多的記憶體去處理多次優化。但是,當我們在低記憶體的安卓手機上執行這段程式碼的時候,很難保證客戶端擁有足夠的記憶體來進行這一系類優化,所以在這種情況下,我們會犧牲一些在PC上的優化,從而佔用更低的記憶體。
這裡寫圖片描述


最後,我們看下執行在伺服器上的js,例如node.js。在這種情況下,我們一般認為,伺服器只會啟動一次(大部分情況),然後會一直保持執行並且處理請求。所以,這時候你不會過多關注它的啟動花費,甚至你希望它儘可能的在初始化的時候去優化所有程式碼,來保證執行時的速度。所以,它的策略如下:
這裡寫圖片描述
但是,還有一種特殊情況,那就是IOT裝置。在IOT裝置上,你不得不考慮記憶體的限制,所以需要犧牲一些優化來降低記憶體:
這裡寫圖片描述

通過上面的幾個例子,我們可以看到哪怕一個簡單的javascript函式,都要幾種不同的優化方式針對不同的環境,不同的裝置。而現在的V8主要做的就是根據不同的情況,由引擎決定是偏向peak performance或者low memory,或者想要更快的啟動。
所以,目前最新版的V8已經採用了一個全新的編譯架構來替代過去的編譯路線。下面我們通過一張圖看看兩個不同的編譯架構。
這裡寫圖片描述
之前的V8引擎主要由Full-codegen和Crankshaft組成。Full-codegen是成程式碼並且不帶優化的快速生編譯器,而Crankshaft則是執行效率高、優化過的程式碼的慢速編譯器。但是在新版的V8種,這些都已經被完全替換了。
為了更好的均衡不同條件的下的優化,以及為了更好的支援webassembly,V8新加了直譯器,並且用TurboFan代替過去的Crankshaft履行優化的職責。(上圖中的黃色部分和Crankshaft都已經不存在了)下面我們來看看V8的裡面包含的內容

TurboFan

TurboFan是一個包含優化過程的編譯器。作為一個優化編譯器,新的TurboFan能夠生成效能更好的原生程式碼,並且支援優化在ES2015以及ES2016,17規範中出現的新特性,如Try,catch,finally這些現在以及能夠得到最好的優化了。同時,V8也填補了過去一些個性能方面的坑。 另外TurboFan也支援WASM的優化。

Ignition Interpreter

Ignition 是用來處理一種情形的,程式的初始化需要很快,但是卻有著較低的記憶體空間。Ignition 是一個直譯器,我們在上面提到過,如果你在合適的時候去使用直譯器,它的效果會好過編譯器。通過Ignition 的處理,會生成可供執行的位元組碼,這種位元組碼的方式對於加速那些大型頁面載入有很大的幫助。

Ignition可以與TurboFan一起工作,它會觀察並發現哪些方法是經常被使用的,對於這些方法可以送到TurboFan進行優化。它倆一起就可以實現對不同的情況做出最好的優化,無論是低記憶體,高效能之類,並且對於node.js的支援也更完善。

Orinoco

Orinoco是新版V8種的並行垃圾回收器。在之前的V8垃圾回收器在並行處理這塊並不好,而現在的Orinoco通過多執行緒處理,極大的提高了垃圾回收器的效能,減少在清理記憶體時可能對程式造成的影響。目前我只從開發者大會的介紹中瞭解到一些它的情況,想要深入研究的可以下載最新的原始碼看看。

V8的benchMark

網頁效能測試從07年到現在總共經歷了數個階段。從最初的只是用一些特別的語法,諸如迴圈1E7次,做特定的效能測試;從12年開始,效能測試轉為用編寫好的靜態應用測試頁面,例如pdf.js之類,儘量模擬真實環境進行測試。而到現在,效能測試已經從靜態測試轉為動態測試。測試不再基於某一特定方面或者某一靜態頁面,而是通過測試真實網頁行為,如逛亞馬遜和淘寶,觀看youtube視訊,通過這樣的real-world page來獲取瀏覽器特近使用者的真實效能。

所以,之前的基準測試工具Octane也已經被廢棄了。目前google的基準測試都採用Speedometer,這個工具會在不久後可以到browerbench.org找到。通過這個最新的工具測試V8的效能在不同平臺上都有著20%-35%的提升。

Speedometer不光測試使用者瀏覽的真實頁面,也同樣支援目前流行的大多數框架應用,諸如MVC,babel,react,Angular,Vue等,並且將會支援webkit。

V8對於ES2015的優化

在之前版本的V8中,對於ES2015或者更高版本的語法實現,在初始化上都會很慢,因為引擎會花費更多的時間(相比ES5)去優化它。

所以,google通過一個名叫“6 speed”的工具完成對新語法的優化。6-speed可以去比較ES2015 版本的程式碼和它的transpiled version之間的差異,從而對ES2015進行優化。通過這個工具,目前最新的V8已經實現了對諸如for of,Object.assign,iteration,spread等新語法特性的優化,在效能上從最初的接近3倍的差距到現在的幾乎相當。所以呢,作為一個web開發者,已經沒有理由不去用新版ES中那些高階語法了更方便的完成你的工作了。

特別值得一提的:目前最熱門的非同步語法,async/await相比之前得到了4.5倍的提升。

關於Dev Tools

瀏覽器的開發者工具一直是所有開發人員依賴的重要法寶,而dev tools的升級,也意味著可以更好的幫助開發人員進行開發工作。下面將介紹一些,

  1. 在canary中可以看到一個新增的Coverage工具。這個工具可以偵測在程式執行過
    程究竟有哪些函式被使用了。比如,你在頁面編寫中引用了一個程式碼可能有幾千行的庫,你在除錯過程中想要知道這個庫中究竟有哪些程式碼是你需要的,通過Coverage工具,你可以很清楚的看到哪些函式被執行,而哪些是根本沒有被用到過的。再進一步,這個工具可以自動幫你清除那些無用的程式碼,一個6000行的庫,在程式碼清除優化後,留下了的不到1400多行。

    在大型工程中,常常會引入很多的依賴庫,使用Coverage你可以快速而且清楚的知道,哪些依賴或函式或者具體程式碼是你需要的並且會使用的,哪些依賴的你可以刪除來對你的程式進行瘦身。
    此外,新版的performance
    panel配合Coverage可以看到在Coverage使用到的函式,它們的執行過程中所耗費的時間,來幫助你更準確的去優化你的程式碼。

  2. 新版的V8對async的除錯,進行了很大的改進,開發者現在可以很方便的對async這類語法進行除錯。

WebAssembly

在最後介紹的就是這兩年異常火熱的WebAssembly(WASM),WASM最初起源與asm.js專案,後來幾家巨頭看到這個技術,覺得就是javascript的出路,因為傳統的優化技術似乎對js效能的提升越來越小了。而asm.js的效能可以堪比原生程式碼,所以在google,微軟,Mozilla等公司的支援下,WebAssembly誕生。目前,V8對WASM提供了支援。此外,還有firefox對它提供了支援,而IE Edge以及webkit的預覽版也提供了支援。

WASM到目前來說,仍然相當新的技術,但已經成了幾家瀏覽器廠商共同支援的技術,這也是第一個自提出就被幾家不同瀏覽器所支援的技術。通過WASM,開發者可以用c,c++開發,通過Emscripten編譯成web應用並且在chrome上執行。目前WASM技術也有很多成熟的例子,比如虛幻引擎製作的頁面,或者一個Unity game。

總結

新版的V8在優化執行上,可以根據不同的環境,不同的裝置來做出最合適的優化。同時對ES2015高階語法也提供了更好的優化,讓開發者放心的使用,同時對node.js提供了更好的除錯支援。最後,關於WebAssembly,WebAssembly可以進一步提升javascript或者引擎執行程式碼的速度,以後會有更多這方面的應用出現。