V8垃圾回收機制

原文地址
本文是深刻淺出nodejs的部分學習筆記javascript

V8內存限制

在node中javascript能使用的內存是有限制的,64位系統下約爲1.4GB,32位系統下約爲0.7GBjava

這個限制在node啓動的時候能夠經過傳遞--max-old-space-size 和 --max-new-space-size來調整,如:node

node --max-old-space-size=1700 app.js //單位爲MB
node --max-new-space-size=1024 app.js //單位爲MB

上述參數在V8初始化時生效,一旦生效就不能再動態改變。算法

V8垃圾回收機制

V8的內存分代

在V8中主要將內存分爲新生代和老生代。新生代中的對象爲存活時間較短的對象,老生代中的對象爲存活時間較長或常駐內存的對象。swift

V8堆的總體大小就是新生代所用內存加上老生代全部內存。前面提到的--max-old-space-size用來設置老生代內存空間的最大值,--max-new-space-size用來設置新生代內存空間的最大值。app

Scavenge算法

新生代中的對象主要經過Scavenge算法進行垃圾回收。在Scavenge的具體實現中,主要採用Cheney算法。ide

Cheney算法是一種採用複製的方式實現的垃圾回收算法,它將堆內存一分爲二,這兩個空間中只有一個處於使用中,一個處於閒置狀態。處因而使用狀態的空間稱爲From空間,處於閒置的空間稱爲To空間。分配對象時,先是在From空間中進行分配,當開始垃圾回收時,會檢查From空間中的存活對象,並將這些存活對象複製到To空間中,而非存活對象佔用的空間被釋放。完成複製後,From空間和To空間的角色互換。簡而言之,垃圾回收過程當中,就是經過將存活對象在兩個空間中進行復制。學習

Scavenge算法的缺點是隻能使用堆內存中的一半,但因爲它只複製存活的對象,對於生命週期短的場景存活對象只佔少部分,因此在時間效率上有着優異的表現。ui

以上所說的是在純Scavenge算法中,可是在分代式垃圾回收的前提下,From空間中存活的對象在複製到To空間以前須要進行檢查,在必定條件下,須要將存活週期較長的對象移動到老生代中,這個過程稱爲對象晉升。spa

對象晉升的條件有兩個,一種是對象是否經歷過Scacenge回收:

令一種狀況是當To空間的使用應超過25%時,則這個對象直接晉升到老生代空間中。

Mark-Sweep 和 Mark-Compact

在老生代中的對象,因爲存活對象佔比較大,再採用Scavenge方式會有兩個問題:一個是存活對象就較多,複製存活對象的效率將會下降;另外一個依然是浪費一半空間的問題。爲此,V8在老生代中主要採用Mark-Sweep和Mark-Compact相結合的方式進行垃圾回收。

Mark-Sweep是標記清除的意思,它分爲標記和清楚兩個階段。與Scavenge相比,Mark-Sweep並不將內存空間劃分爲兩半,因此不存在浪費一半空間的行爲。與Scavenge複製活着的對象不一樣,Mark-Sweep在標記階段遍歷堆中的全部對象,並標記活着的對象,在隨後的清理階段中,只清除沒有被標記的對象。能夠看出,Scavenge只複製活着的對象,而Mark-Sweep只清理死亡對象。活對象在新生代中只佔較小部分,死對象在老生代中只佔較小部分,這就是兩種回收方式能高效處理的緣由。

Mark-Sweep在老生代空間中標記後的示意圖:

Mark-Sweep最大的問題在於進行一次標記清楚後,內存會出現不連續的狀態,這種會致使後續須要分配一個大對象的時候,沒法完成分配,就會提早出發垃圾回收,而此次回收是沒必要要的。

爲了解決Mark-Sweep的內存碎片問題,Mark-Compact被提出來,它是在Mark-Sweep的基礎上演變而來的,差異在於對象在標記爲死亡後,在整理的過程當中,將活着的對象往一端移動,移動完成後,直接清理掉邊界外的對象。

3種回收算法的簡單比較:

回收算法 Mark-Sweep Mark-Compact Scavenge
速度 中等 最慢 最快
空間開銷 少(有碎片) 少(無碎片) 雙倍空間(無碎片)
是否移動對象

若是你們對美股、感興趣, 也能夠點擊美股指南

相關文章
相關標籤/搜索