V8 —— 你需要知道的垃圾回收机制
生活随笔
收集整理的這篇文章主要介紹了
V8 —— 你需要知道的垃圾回收机制
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前言
V8 blog近日發布了文章描述了“并發標記”的新技術,提升標記過程的效率。并發標記是一個主要用新的平行和并發的垃圾收集器替換舊的垃圾回收器的項目,現在Chrome 64和Node.js v10已經默認啟用并發標記。講解之前我們先回顧一下基本知識點。基本概念
弱分代假設(The Weak Generational Hypothesis)
新生代與老生代
新生代包括一個New Space,老生代包括: Old Space, Code Space和Map Space,Large Object Space。64位環境下的V8引擎的新生代內存大小32MB、老生代內存大小為1400MB,而32位則減半,分別為16MB和700MB。對于新生代的對象,采用空間換取時間的Scavenge算法, 盡可能快的回收內存。如果對象經歷了2次GC還依然堅挺,就會在第二次回收時晉升為老生代(準確的說是保存在Old Space中)。而老生代的GC采取Mark-Sweep的算法,并使用Mark-Sweep解決內存碎片的問題。Scavenge算法
對于新生代對象,采用Scavenge算法來回收。簡單來說,將內存的空間分為兩個semispace,同一時刻只有一個空間處于使用中。使用中的叫做 to space,不被使用的叫做 from space。分配對象時,先在From空間分配,垃圾回收時檢查(寬度優先)From空間的存活對象,將存活對象復制到To空間,清理非存活對象,復制后,空間身份發生對調。Mark-Sweep算法
處理老生代對象時,采用深度優先掃描,用三色標記的算法。V8使用每個對象的兩個mark-bits和一個標記工作棧來實現標記。兩個mark-bits編碼三種顏色:白色(00),灰色(10)和黑色(11)。白色表示對象可以回收,黑色表示對象不能回收,并且他的所有引用都被便利完畢了,灰色表示不可回收,他的引用對象沒有掃描完畢。掃描過程:Mark-Compact算法
在對象標記死亡后,在整理的過程中,將活著的對象向另一個內存頁移動,移動完后內存頁就可以還給操作系統,但如果這一頁的活動對象被很多其他頁的對象引用,就不會compact,因為移動完后更新其他引用的指針開銷大。全暫停與增量標記
垃圾回收的3種基本算法需要應用邏輯暫停下來,垃圾回收完后恢復應用程序邏輯,即“全暫停”,過長的停頓會讓用戶感到卡頓,所以為了降低全堆的垃圾回收,當堆的大小到一定程度后,開始增量GC,V8在標記階段將標記的動作分為很多小“步進”,應用邏輯與垃圾回收交替進行直到標記階段完成。但是,對于過大的堆,GC在試圖跟上應用程序分配速度的過程中,仍有長時間的停頓,并且應用程序需要通知GC對象圖的所有變化,這些都是需要成本的(寫保障 write-barrier)。V8使用Dijkstra-style 的寫屏障(write-barrier)來實現通知。當object.field = value in JavaScript時,V8會插入以下代碼:// Called after `object.field = value`. write_barrier(object, field_offset, value) {if (color(object) == black && color(value) == white) {set_color(value, grey);marking_worklist.push(value);} } 復制代碼write-barrier可以保障不會出現黑色對象指向了白色對象的現象發生(強三色不變形 strong tri-color invariant),這樣應用程序不會在GC時誤刪活動對象。在GC完成后所有白色對象都是可安全刪除的。但是,由于write-barrier的損耗,降低了應用程序的吞吐量,所以需用其他的worker threads提高吞吐量,使worker threads也可以進行標記的工作。這就是下面要講的平行標記和并發標記。平行標記 parallel marking
平行標記期間,應用程序暫停,main thread和worker thread共同執行標記操作,下圖顯示了平行標記所涉及的數據結構。箭頭指示數據流的方向。其中,對象圖是只讀的,不允許去修改他,Mark-bits和Marking worklist是可以讀和寫的。Marking worklist負責決定分給其他worker thread的工作量,決定了性能與保持本地線程的均衡,所以如何高效地完成工作的分配至關重要。如下圖所示,V8使用基于內存段的方式去平衡各個線程的工作量,避免線程同步的耗時與盡可能的工作。并發標記 concurrent marking
并發標記允許標記行為與應用程序同時進行。這就需要解決數據競爭的問題,比如JS代碼在更改一個對象的字段,而worker thread又在標記字段,就可能導致錯誤的垃圾回收。所以main thread需要與worker threads在發生數據競爭時進行同步,大多數的數據競爭行為通過輕量級的原子級內存訪問就可以同步,但是一些特殊的場景需要獨占整個對象的訪問。優化的結果
有了平行標記與并發標記后,對比上面講的流程,GC的流程變為:參考文獻:
- Concurrent marking in V8
- 解讀 V8 GC Log
- 思維導圖:github.com/bailinlin/A…
總結
以上是生活随笔為你收集整理的V8 —— 你需要知道的垃圾回收机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL-MMM架构部署(有图)
- 下一篇: Hadoop_23_MapReduce倒