無論是高級語言,仍是低級語言。內存的管理都是:node
前兩步,你們都沒有太大異議。關鍵是釋放內存這一步,各類語言都有本身的垃圾回收(garbage collection, 簡稱GC)機制。作GC的第一步是判斷堆中存的是數據仍是指針,是指針的話,說明它被指向活躍的對象。有3種判斷方法:算法
對於JavaScript而言,最初的垃圾回收機制,是基於引用計次來作的。後來升級爲標記清除。瀏覽器
當對象被引用次數爲0時,就被回收。潛在的一個問題是:循環引用時,兩個對象都至少被引用了一次,將不能自動被回收。因此致使,咱們常講的內存泄露。函數
// 引用計次 var a = {t: 1}; // 對象 `{t: 1}` (如下簡稱obj)被引用一次 var b = a; // obj 被引用兩次 a = null; // obj 如今爲1次 b = null; // obj 如今爲0次,可回收 // 循環引用 function fn() { var a = {}; var b = {}; a.b = b; b.a = a; } fn();
這是當前主流的GC算法,V8裏面就是用這種。當對象,沒法從根對象沿着引用遍歷到,即不可達(unreachable),進行清除。對於上面的例子,fn()
裏面的 a
和 b
在函數執行完畢後,就不能經過外面的上下文進行訪問了,因此就能夠清除了。post
下面,咱們簡述下V8的GC機制:spa
在大部分的應用場景:一個新建立的對象,生命週期一般很短。因此,V8裏面,GC處理分爲兩大類:新生代和老生代。指針
新生代的堆空間爲1M~8M,並且被平分紅兩份(to-space和from-space),一般一個新建立的對象,內存被分配在新生代。當to-space滿的時候,to-space和form-space交換位置(此時,to空,from滿),並執行GC.若是一個對象被判定爲,未被引用,就清除;有被引用,逃逸次數+1(若是此時逃逸次數爲2,就移入老生代,不然移入to-space)。code
老生代的堆空間大,GC不適合像新生代那樣,用平分紅兩個space這種空間換時間的方式。老生代的垃圾回收,分兩個階段:標記、清理(有Sweeping和Compacting這兩種方式)。orm
標記,採用3色標記:黑、白、灰。步驟以下:對象
GC的時候,從根對象開始遍歷。在瀏覽器,根對象是 window
;在 Node.js 中,是 global
(或稱爲root
).
Node.js中,每一個文件被當作一個模塊,因此,當你用 var/let/const
在文件的全局,聲明變量的時候,做用域是當前文件(模塊)。所以,圖中 root.a
是 undefined
.