Google V8的垃圾回收引擎

jopen 9年前發布 | 11K 次閱讀 V8

 

Google V8 引擎(以下簡稱V8)是 Google 的一個開源項目,旨在構建一個高效的 JavaScript 引擎,是Google特別為Chrome高速運行網頁應用(Web App)而開發的。同時,它可以作為一個獨立的庫被嵌入到其他應用程序中,以提高軟件的靈活性和可擴展性。目前,V8引擎由于其高效的性能吸引了越來越多 的關注。

Google的好幾款應用都是基于JavaScript,其中包括Gmail電子郵件服務、Google Maps地圖數據服務、以及Google Docs office套件。這些應用表現出的速度不僅受到服務器、網絡、渲染引擎(Rendering Engine)等因素的影響,同時也受到JavaScript本身執行速度的影響。而Google研發的V8 JavaScript引擎通過采取一系列關鍵技術,大大提升了JavaScript的執行速度,關鍵技術包括JIT編譯 (JIT Compile)、 垃圾回收(Garbage Collection) 、內嵌緩存(Inline Cache)、隱藏類等。在本文中,重點對V8的垃圾回收引擎進行簡單介紹。

什么是垃圾回收

JavaScript的性能是關系到Chrome價值的一個重要方面,因為它涉及到用戶能否獲得一個流暢的使用體驗。從Chrome41版本開始,通過在一些小的、零散的空閑時間內執行昂貴的內存管理操作,V8提高了Web應用程序的響應能力。

許多腳本語言引擎,如V8引擎,對運行的應用程序實施動態的內存管理。引擎可以定期檢查分配給應用程序的內存,確定哪些數據不再需要,并清除出 來,以騰出內存空間。這個過程被稱為垃圾回收。垃圾回收可以大幅簡化程序的內存管理代碼,降低程序員的負擔,減少因長時間運轉而帶來的內存泄露問題。

什么時候執行垃圾回收

Chrome 41版本包括了一個 針對渲染引擎的任務調度器(Task Scheduler) ,以確保Chrome瀏覽器一直保持響應和流暢,任務調度器使延遲敏感的任務擁有更高的優先級。為了實現這一目標,任務調度器需要獲取多種信息,包括系統 的繁忙程度,哪些任務需要被執行,以及這些任務的緊迫程度。在此基礎上,任務調度器可以評估Chrome什么時候可能空閑,以及預計會空閑多久。

舉一個簡單的例子,當Chrome在網頁上播放一段視頻的時候。視頻在屏幕上的更新速率為60幀每秒(FPS),即Chrome大概每次有 16.6ms的時間來進行更新。這樣,Chrome將在前一幀顯示后立刻啟動當前幀的工作,為當前幀執行輸入和渲染任務。如果Chrome完成所有這些工 作用時不到16.6ms,在剩下的時間內, Chrome瀏覽器處于閑置狀態。此時,調度器通過調度一些特殊的空閑任務(Idle Tasks)可以使Chrome能夠利用這些空閑時間。如下圖所示。

Google V8的垃圾回收引擎

空閑任務是一些特殊的低優先級任務,它們在調度器確定Chrome空閑的時候才被運行。空閑任務擁有一個截止時間,截止時間是調度器估計 Chrome能夠保持空閑的時間。例如,在視頻播放的例子中,截止時間是下一幀應該開始的時間。在其他情況下,截止時間可能是下一個待處理任務計劃運行的 時間,通常其有一個50ms的上限,以確保Chrome瀏覽器對突然的用戶輸入仍能保持響應。空閑任務的截止時間能夠被用來估算在不會造成用戶輸入響應延 遲的情況下Chrome可以完成的工作量。

垃圾回收就是一種典型空閑任務,其隱藏在一些關鍵的、延遲敏感的任務背后。這意味著這些垃圾回收任務是在沒有影響用戶體驗的情況下,在Chrome的空閑時間內被執行。為了理解V8是如何做到這一點,下面我們對V8目前的垃圾回收策略進行深入了解。

深入了解V8的垃圾回收引擎

V8采用了一個 分代(Generational)垃圾回收器 ,將內存堆分割為新生代(Young Generation)和老生代(Old Generation)。新生代的對象為存活時間較短的對象,老生代中的對象為存活時間較長或常駐內存的對象。由于絕大多數對象的生存期很短,只有少數對 象的生存期較長,這種分代策略能使垃圾回收器對新生代對象執行一些規則的、小的垃圾回收(被稱為Scavenge)。V8分別對新生代對象和老生代對象使 用不同的垃圾回收算法來提升垃圾回收的效率。

對象起初會被分配在新生代內存區(通常很小,只有1-8 MB,具體根據任務分配)。大多數的對象被分配在這里,這個區域很小但是垃圾回收特別頻繁。新生代使用 半空間(Semi-space) 分配策略,其中新對象最初分配在新生代的活躍半空間內。一旦半空間已滿,一個Scavenge操作將活躍對象移出到其他半空間中,被認為是長期駐存的對象,并被晉升為老生代。一旦活躍對象已被移出,則在舊的半空間中剩下的任何死亡對象被丟棄。

因此新生代對象的Scavenge操作的持續時間取決于新生代中活躍對象的數量。在大部分新生代對象活躍時間不長的情況下,一個Scavenge 操作非常快(<1ms)。然而,如果大多數對象都需要被Scavenge的時候,Scavenge操作的持續時間顯然會更長。

Scavenge操作對于快速回收、緊縮小片內存效果很好,但對于大片內存則消耗過大。因為Scavenge操作需要出區和入區兩個區域,這對于小片內存 尚可,而對于超過數MB的內存就開始變得不切實際了。老生代所保存的對象大多數是生存周期很長的甚至是常駐內存的對象,而且老生代占用的內存較多,通常包 含有上百MB的數據。因此,V8在老生代中的垃圾回收采用 標記-清除(Mark-Sweep) 和Mark-Compact相結合的策略。

當老生代中的活動對象增長超過了一個預設的限制的時候,將對堆棧執行一個大回收。老生代垃圾回收使用Mark-Sweep策略,其采用了幾種優化方法來改 善延遲和內存消耗。標記時間取決于必須標記的活躍對象的數目,對于一個大的web應用,整個堆棧的標記可能需要超過100ms。由于全停頓會造成了瀏覽器 一段時間無響應,所以V8使用了一種 增量標記的方式標記活躍對象 ,將完整的標記拆分成很多小的步驟,每做完一部分就停下來,讓JavaScript的應用線程執行一會,這樣垃圾回收與應用線程交替執行。V8可以讓每個標記步驟的持續時間低于5ms。

由于標記完成后,所有對象都已經被標記,即不是活躍對象就是死亡對象,堆上有多少空間已經確定。清除時,垃圾回收器會掃描連續存放的死對象,將其 變成空閑空間。這個任務是由專門的清掃線程同步執行。最后,為減少老生代對象產生的內存碎片,還要執行內存緊縮(Memory Compaction)。這個任務可能是非常耗時的,并且僅當內存碎片成為問題的時候才進行。

總之,有四個主要的垃圾回收任務:

  1. 新生代對象的Scavenge,這通常是快速的;

  2. 通過增量方式的標記步驟,依賴于需要標記的對象數量,時間可以任意長;

  3. 完整垃圾回收,這可能需要很長的時間;

  4. 帶內存緊縮的完整垃圾回收,這也可能需要很長的時間,需要進行內存緊縮。

為了在空閑時段執行這些操作,V8給任務調度器公布垃圾回收空閑任務。當這些空閑任務運行時,它們被提供一個需要完成的截止時間。 V8的垃圾回收空閑時間處理程序為了減少內存消耗,評估哪些垃圾回收任務應該被執行,同時緊盯截止時間以避免在幀渲染過程中出現用戶輸入響應延遲。

如果應用的內存分配率顯示在下一個期待的空閑時間之前新生代內存區已經滿了,垃圾回收器將執行新生代對象的Scavenge操作。此外,它還會計 算最近的Scavenge操作所花費的平均時間,可以幫助預測未來Scavenge操作的持續時間,并確保它不會超出空閑任務的截止時間。

當老生代中活躍對象的數量接近堆棧限制的時候,增量標記開始。增量標記的步數與需要標記的字節數成線性比例。根據測得的平均標記速度,垃圾回收空閑時間處理程序嘗試盡可能地為一個垃圾回收任務安排多的標記工作。

如果老生代內存區幾乎滿了,此外任務的截止時間足夠長可以完成回收任務,在一個空閑任務中將調度一個完整的垃圾回收任務。回收任務的執行時間是標記速度乘以分配對象的數目。帶內存緊縮的完整垃圾回收只有在Chrome空閑足夠長的時間才被執行。

性能評價

為了評價空閑時間運行垃圾回收任務的影響,V8使用Chrome的 性能遙測基準框架 ,以評價加載熱門網站時頁面滾動的平滑度。選擇Linux工作站上排名 前25位的網站 ,以及Android Nexus 6智能手機上的一些 典型的移動網站 ,在兩種情況下打開流行的網頁(包括一些復雜的web應用,如Gmail,Google文檔和油Tube),滾動其內容需要幾秒鐘。 為了保證流暢的用戶體驗,Chrome的目標是滾動顯示保持在60 FPS。

下圖顯示了空閑時間垃圾回收的比例。相比Nexus 6,工作站因為擁有更好的硬件,導致總體上擁有更多的空閑時間,從而導致其在空閑時間內擁有一個更高的垃圾回收比例(43%,而Nexus6為31%),工作站的 jank指標 比Nexus 6也高了7%。

Google V8的垃圾回收引擎

事實上,垃圾回收是一個復雜的過程。Google V8的垃圾回收方法能夠自動完成垃圾回收,大大減輕了應用開發者的負擔,能夠讓他們集中精力于更重要的事情上。盡管目前V8的垃圾回收引擎并不完美,仍存 在一些性能問題而且偶爾會出現奇怪的現象,但我們還是很高興地看到其正在變得更好,Google的工程師Hannes Payer和Ross McIlroy在其 博客 中說到,他們一直在努力對垃圾回收做更多的改進。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!