垃圾回收技術

發展史

2011 年,V8 從 stop-the-world 標記切換到增量標誌。

2018 年,GC 技術又有了一個重大突破,這項技術名爲併發標記。在Chrome 64和Node.js v10中已啓用。他將標記時間縮短了60%~70%。還有「Parallel Scavenger」技術,它將新生代的垃圾回收時間縮短了20%~50%。

 

全停頓(Stop The World)

特點:應用邏輯暫停,全力執行垃圾回收

描述:垃圾回收算法在執行前,需要將應用邏輯暫停,執行完垃圾回收後再執行應用邏輯,這種行爲稱爲 「全停頓」(Stop The World)。例如,如果一次GC需要100ms,應用邏輯就會暫停100ms。

缺點:全停頓的策略導致垃圾回收中不能及時響應用戶的輸入,而且如果有動畫會造成動畫效果的卡頓

 

增量垃圾回收(Incremental)

特點:垃圾回收任務和JS邏輯交錯的進入主線程執行

描述:增量式垃圾回收是主線程間歇性的去做少量的垃圾回收的方式。不會在增量式垃圾回收的時候執行整個垃圾回收的過程,只是整個垃圾回收過程中的一小部分工作。做這樣的工作是極其困難的,因爲 JavaScript 也在做增量式垃圾回收的時候同時執行,這意味着堆的狀態已經發生了變化,這有可能會導致之前的增量回收工作完全無效。從圖中可以看出並沒有減少主線程暫停的時間(事實上,通常會略微增加),只會隨着時間的推移而增長。但這仍然是解決問題的的好方法,通過 JavaScript 間歇性的執行,同時也間歇性的去做垃圾回收工作,JavaScript 的執行仍然可以在用戶輸入或者執行動畫的時候得到及時的響應。如果直接進行長時間的GC,會導致應用暫停和無響應,將會導致糟糕的用戶體驗。從2011年起,v8就將全停頓標記換成了增量標記。改進後的標記方式,最大停頓時間減少到原來的1/6。

缺點:1.並沒有減少主線程暫停的時間(事實上,通常會略微增加)。

        2.由於寫入屏障(Write-barrier )機制的成本,增量標記可能會降低應用程序的吞吐量。

 

 

由於寫入屏障(Write-barrier )機制的成本,增量標記可能會降低應用程序的吞吐量。但通過使用額外的工作線程可以提高吞吐量和暫停時間。以下兩種方法可以在工作線程上進行標記:並行標記和併發標記。

 

並行標記(Parallel)

特點:主線程和協助線程在一時間做同樣的任務

描述:並行是主線程和協助線程同時執行同樣的工作,但是這仍然是一種 ‘stop-the-world’ 的垃圾回收方式,但是垃圾回收所耗費的時間等於總時間除以參與的線程數量(加上一些同步開銷)。因爲沒有 JavaScript 的執行,因此只要確保同時只有一個協助線程在訪問對象就好了。

併發標記(Concurrent)

特點:垃圾回收任務完全發生在後臺,主線程可以自由的執行JavaScript。

描述:併發是主線程一直執行 JavaScript,而輔助線程在後臺完全的執行垃圾回收。這種方式是這三種技術中最難的一種,JavaScript 堆裏面的內容隨時都有可能發生變化,從而使之前做的工作完全無效。最重要的是,現在有讀/寫競爭(read/write races),主線程和輔助線程極有可能在同一時間去更改同一個對象。這種方式的優勢也非常明顯,主線程不會被掛起,JavaScript 可以自由地執行 ,儘管爲了保證同一對象同一時間只有一個輔助線程在修改而帶來的一些同步開銷。

Chrome當前使用的技術

現今,V8 在新生代垃圾回收中使用並行標記,每個協助線程會將所有的活動對象都移動到 ‘To-Space’。在每一次嘗試將活動對象移動到 ‘To-Space’ 的時候必須通確保原子化的讀和寫以及比較和交換操作。不同的協助線程都有可能通過不同的路徑找到相同的對象,並嘗試將這個對象移動到 ‘To-Space’;無論哪個協助線程成功移動對象到 ‘To-Space’,都必須更新這個對象的指針,並且去維護移動這個活動對象所留下的轉發地址。以便於其他協助線程可以找到該活動對象更新後的指針。爲了快速的給倖存下來的活動對象分配內存,清理任務會使用線程局部分配緩衝區。

V8 中的主垃圾回收器主要使用併發標記,一旦堆的動態分配接近極限的時候,將啓動併發標記任務。每個輔助線程都會去追蹤每個標記到的對象的指針以及對這個對象的引用。在 JavaScript 執行的時候,併發標記在後臺進行。寫入屏障(write barriers)技術在輔助線程在進行併發標記的時候會一直追蹤每一個 JavaScript 對象的新引用。當併發標記完成或者動態分配到達極限的時候,主線程會執行最終的快速標記步驟;在這個階段主線程會被暫停,這段時間也就是主垃圾回收器執行的所有時間。在這個階段主線程會再一次的掃描根集以確保所有的對象都完成了標記;然後輔助線程就會去做更新指針和整理內存的工作。並非所有的內存頁都會被整理,加入到空閒列表的內存頁就不會被整理。在暫停的時候主線程會啓動併發清理的任務,這些任務都是併發執行的,並不會影響並行內存頁的整理工作和 JavaScript 的執行。

名詞解析

寫入屏障(write barriers: 內存屏障(英語:Memory barrier),也稱內存柵欄,內存柵障,屏障指令等,是一類同步屏障指令,它使得 CPU 或編譯器在對內存進行操作的時候, 嚴格按照一定的順序來執行

參考鏈接:

https://blog.csdn.net/weixin_33724059/article/details/86720543

https://www.jianshu.com/p/b8ed21e8a4fb

https://zhuanlan.zhihu.com/p/55917130

https://www.oschina.net/translate/v8-javascript-engine

 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章