NodeJS V8的垃圾回收機制

摘自《NodeJS深入淺出》:

V8的內存限制:

在Node中通過JavaScript使用內存只能使用部分內存(64位系統下爲1.4GB,32位系統下爲0.7GB)。
造成這樣的問題主要原因在於Node基於V8構建,Node在使用的JavaScript對象基本上都是通過V8自己的方式來進行分配和管理。這套內存管理機制在瀏覽器下使用綽綽有餘,但在Node中,就被束縛了。

爲什麼要限制內存大小?

表層原因是因爲V8最初爲瀏覽器而設計,不太可能遇到大的內存使用場景。深層原因是V8的垃圾回收機制的限制。
按照官方的說法:如果以1.5GB的垃圾回收堆內存爲例,V8做一次小的垃圾回收需要50ms以上,一次增量式的需要1s以上,這會引起JavaScript線程暫停執行的時間。
但也有額外的方法可以放寬V8的內存限制:
node --max-old-space-size=1700 test.js //單位爲MB
//或者
node --max-new-space-size=1024 test.js //MB

那麼我們如何跳出這樣的枷鎖呢?

V8的垃圾回收機制:

  • V8主要用到的各種垃圾回收算法:

V8的垃圾回收策略主要基於分代式垃圾回收機制。
在實際垃圾回收過程中,沒有一種垃圾回收算法能能夠勝任所有場景,由於不同的對象生命週期不同,所以只能針對特定的情況使用不同的算法纔能有更好的效果。

  • V8的內存分代

在V8中,內存主要分爲新生代和老年代,新生代中的對象爲存活週期較短的對象,老生代中的對象爲存活週期長和常駐內存的對象:
在這裏插入圖片描述
V8堆的整體大小就是新生代所用內存空間加上老生代的內存空間。

  • Scavenge算法(複製清除)

Scavenge算法採用的是Cheney算法(複製清除),它將堆內存一分爲二,每一部分空間稱之爲"semispace"。在這兩個空間中,只有一個處於使用中,一個處於空閒中。處於使用的稱爲From空間,處於閒置的稱爲To空間。
當我們分配對象的時候,現在From空間中進行分配,並開始進行垃圾回收時。會檢查From空間中的存活對象,這些存活對象將被複制到To空間中,而非存活對象佔用的空間會被釋放。完成複製後,From空間和To空間的角色互換。
但該算法的缺點是每次只能使用堆內存額一半。由於該算法只複製存貨的對象,並且對於生命週期短的場景存活對象只佔少部分,所以它在時間效率上的表現優異
在這裏插入圖片描述
當一個對象經過多次複製依然存活的時候,它將會被認爲是生命週期較長的對象,這種對象會被移動到老生代中採用新的算法進行管理,這種移動稱爲“晉升
默認情況下,V8的對象分配主要集中在From空間中,複製期間檢查內存地址來判斷是否被複制過,如果是,則晉升至老生代中,否則複製到To空間中
還有一個判斷條件是To空間的內存佔用比,當要從From空間複製一個對象到To孔家時,如果To空間使用內存超過25%,則也會晉升至老生代空間中。
爲什麼會有25%這個內存限制?
因爲當回收一次後,這個To空間就變爲From空間,接下來的內存分配將在這個空間進行,如果佔比過高,會影響內存分配
缺點

  • 存活對象較多,複製存活對象的效率較低
  • 浪費一半內存空間
  • 如何解決複製清除帶來的問題?(V8主要採用"標記清除"+“標記整理”)

Mark-Sweep(標記清除):
它分爲標記和清除兩個階段,與複製清除相比,標記清除並不將內存空間一分爲二,且清除對象內存的方式也不同,標記清楚在標記階段遍歷堆中的所有對象,並標記活着的對象,在隨後的清除階段中,只清除沒有被標記的對象,
爲什麼標記活着的對象?
因爲活對象在新生代中只佔小部分,死對象在老生代中只佔小部分,這就是能高效處理的原因:
在這裏插入圖片描述
缺點

  • 內存空間會出現不連續的狀態,從而導致出現內存碎片對後續的內存分配造成問題
  • 如何解決內存碎片的問題?(標記整理)

基於標記清除,不同的地方在於,對象在被標記死亡後,在整理的過程中,將活着的對象往一端移動,移動完成後,直接清理邊界外的內存
在這裏插入圖片描述
完成移動後可以直接清除最右邊的內存區域完成回收

算法對比表:

回收算法 標記清除 標記整理 複製清除
效率 中等 最慢 最快
內存開銷 少(有碎片) 少(無碎片) 雙倍空間(無碎片)
是否移動對象

從表中可以看出,由於標記整理需要移動對象,所以它執行的效率不是很高,爲了取捨,V8默認使用了"標記清除",在空間不足以對從新生代晉升過來的對象進行分配時才使用標記整理

V8如何優化垃圾回收帶來的"停頓問題?"

爲了降低全堆垃圾回收帶來的停頓時間,V8先從標記入手,將原本需要一口氣停頓完成的動作改爲增量標記,也就是拆分爲許多小"步進",每做完一個"步進"就讓JavaScript應用執行一會兒,從而完成垃圾回收和應用執行進行交替執行完成標記階段
V8在完成增量標記後,垃圾回收的最大停頓時間可減少到原本的1/6左右
標記完成後,V8在後續的清理採用了延遲清理,整理也採用了增量式整理,同上的道理差不多,在這裏就不多做深究了

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