(譯)V8 JavaScript引擎

改進了代碼緩存

V8使用 從Chrome 66開始,咱們經過在頂層執行後生成緩存來緩存更多代碼。這會致使初始加載時分析和編譯時間縮短20-40%。

背景

V8使用兩種代碼緩存來緩存生成的代碼,以便之後重用。首先是每一個V8實例中都有的內存緩存。初始編譯後生成的代碼存儲在此緩存中,並鍵入源字符串。這能夠在V8的相同實例中重複使用。另外一種代碼緩存序列化生成的代碼並將其存儲在磁盤上供未來使用。該緩存並不特定於V8的特定實例,並可用於V8的不一樣實例。這篇博文主要關注Chrome中使用的第二種代碼緩存。(其餘嵌入程序也使用這種代碼緩存;它不只限於Chrome,但本博文僅關注Chrome中的使用狀況。)

Chrome將序列化的生成代碼存儲在磁盤緩存中,並使用腳本資源的URL將其鍵入。加載腳本時,Chrome會檢查磁盤緩存。若是腳本已被緩存,則Chrome會將序列化數據做爲編譯請求的一部分傳遞給V8。而後V8反序列化這些數據,而不是解析和編譯腳本。還有額外的檢查來確保代碼仍然可用(例如:版本不匹配致使緩存的數據沒法使用)。

真實世界的數據顯示,代碼緩存命中率(對於能夠緩存的腳本)很高(〜86%)。雖然這些腳本的緩存命中率很高,可是咱們每一個腳本緩存的代碼量並非很高。咱們的分析代表,增長緩存的代碼量能夠減小解析和編譯JavaScript代碼大約40%的時間。

增長緩存的代碼量

在之前的方法中,代碼緩存與編譯腳本的請求相結合。

嵌入者能夠請求V8序列化它在頂級編譯新的JavaScript源文件時生成的代碼。編譯腳本後,V8返回了序列化代碼。當Chrome再次請求相同的腳本時,V8會從緩存中獲取序列化的代碼並對其進行反序列化。
V8徹底避免了從新編譯已經在緩存中的函數。
下圖顯示了這些場景:

V8僅編譯在頂層編譯期間預期當即執行的函數(IIFE),並標記用於延遲編譯的其餘函數。
這有助於經過避免編譯不須要的函數來提升頁面加載時間,但這意味着序列化數據僅包含急切編譯的函數的代碼。

在Chrome 59以前,咱們必須在任何執行開始以前生成代碼緩存。較早的V8基本編譯器(Full-codegen)爲執行上下文生成專用代碼。Full-codegen將代碼修補用於特定執行上下文的快速路徑操做。經過刪除要在其餘執行上下文中使用的特定於上下文的數據,不能輕易地序列化此類代碼。

隨着在Chrome 59中 ,這一限制再也不是必要的。點火使用 來執行當前執行環境中的快速路徑操做。上下文相關數據存儲在反饋向量中並與生成的代碼分開。
這已經打開了即便在執行腳本以後也能生成代碼緩存的可能性。在咱們執行腳本時,會編譯更多的函數(標記爲惰性編譯的函數),從而容許咱們緩存更多的代碼。

V8公開了一個新API, ScriptCompiler::CreateCodeCache以請求獨立於編譯請求的代碼緩存。請求代碼緩存以及編譯請求已被棄用,而且不適用於V8 v6.6及更高版本。從版本66開始Chrome使用此API在頂層執行後請求代碼緩存。下圖顯示了請求代碼緩存的新場景。代碼緩存在頂層執行以後被請求,並所以包含在腳本執行期間稍後被編譯的函數的代碼。在後面的運行中(在下圖中顯示爲熱運行),它避免了在頂層執行期間編譯函數。

結果

使用咱們內部的 測量此功能的性能。下圖顯示了早期高速緩存方案中分析和編譯時間的縮短。在大多數頁面上,解析和編譯時間都會減小20-40%左右。

來自wild的數據顯示了相似的結果,在桌面和移動設備上編譯JavaScript代碼的時間減小了20-40%。在Android上,這種優化還能夠轉化爲頂級頁面加載指標減小1-2%,例如網頁成爲互動時所需的時間。咱們還監測了Chrome的內存和磁盤使用狀況,但沒有看到任何明顯的迴歸。

發佈者Mythri Alle,首席代碼Cacher

原文地址:https://v8project.blogspot.com/2018/04/improved-code-caching.htmlhtml

相關文章
相關標籤/搜索