三分鐘快速理解javascript記憶體管理

涼風羽Richard發表於2019-03-04

javascript中具有垃圾自動回收機制(Garbage Collection),也就是執行環境會負責管理程式碼執行過程中使用的記憶體,在開發過程中就可以不考慮記憶體的分配,以及無用記憶體釋放的問題.但是觸發立即回收機制會中斷程式碼的執行,停止其他操作,遍歷所有的物件,回收所有不可訪問的物件,因此垃圾回收的工作機制是週期性的.

因本文為快速理解記憶體管理所以相關涉及的知識:作用域鏈,閉包等概念我在這裡就不做展開,想要去了解的朋友可以直接在掘金上瀏覽相關文章,有很多大牛的優秀文章值得一讀

變數的生命週期

大家都知道javascript有作用域的概念,在區域性作用域內用var關鍵字宣告變數,函式執行結束,如果垃圾回收機制判斷到此區域性變數可以被回收,那麼這個區域性變數就會在記憶體中消失.

    function fn1(){
        var obj = {name: `richard`}
    }
    function fn2(){
        var obj = {name: `jungkkki`}
        return obj
    }
    var a = fn1() // undefined
    var b = fn1() // {name: `jungkkki`}
複製程式碼

fn1在函式內宣告瞭區域性變數obj並且賦值,在函式執行結束後,這個區域性變數便再也無法訪問到了,當垃圾回收機制週期性執行時,這個區域性變數obj將被回收.

fn2在函式內宣告瞭區域性變數obj並且賦值,在函式執行結束後,這個區域性變數返回值賦值給全域性變數b,當垃圾回收機制週期性執行時,{name:`jungkkki`}的記憶體不會被回收.

分享知識點:解釋型語言(例如 JavaScript)來說, 通過詞法分析 -> 語法分析 -> 語法樹,就可以開始解釋執行了。
語法分析成 AST (Abstract Syntax Tree),大家可以在這裡試試 http://esprima.org/

標記清除&引用計數

javascript如何來判斷變數是否可以被訪問那麼就要提到辣雞回收機制中標記清除和引用計數

   function test(){
       var one = {num: `1`} // 標記進入環境
       var two = {num: `2`} // 標記進入環境
   }
   test() // 函式執行完畢 one,two 標記離開環境
複製程式碼

標記清除:通常javascript通過標記變數的狀態來判斷是否被回收,當變數在函式中被宣告時標記進入環境,在函式執行結束時,環境被銷燬標記離開環境等待回收.只要不釋放進入環境的變數,他在環境中的任何位置任何時刻都可以被訪問,就不會被垃圾回收機所回收.

   function test2(){
       var a = {name: `richard`} // {name: `richard`} 引用次數1
       a = {name: `jungkkki`} // {name: `richard`} 引用次數 -1 直接標記,等待回收 {name; `jungkkki`} 引用次數+1
   }
   test() // 函式執行結束 環境銷燬 {name: `jungkkku`}等待回收
複製程式碼

引用計數:javascript去維護一張表,儲存記憶體中資源的引用次數,資源被引用+1,結束引用或者函式執行完畢結束作用域,引用次數-1,引用次數由1到0時不會執行,節省開銷,直接標記

GC 的缺陷、分代回收和增量 GC

和其他語言一樣 GC 會中斷程式碼執行,停止其他操作。因為要遍歷所有物件,回收所有不可訪問物件,這個操作的耗時可能有 100ms 以上。在 V8 引擎新版本中引入了兩種優化方法:1. 分代回收(Generation GC),2. 增量 GC(increment GC)

分代回收:目的是通過物件的使用頻率、存在時長區分新生代與老生代物件。多回收新生代區(young generation),少回收老生代區(tenured generation),減少每次需遍歷的物件,從而減少每次GC的耗時

增量 GC:把需要長耗時的遍歷、回收操作拆分執行,減少中斷時間,但是會增大上下文切換開銷.

喜歡的朋友可以隨手點贊和關注,有大家的支援就有了更多的動力

![](https://user-gold-cdn.xitu.io/2017/10/23/c7095c96db3d54b6d71c17e48fcc3cb0)

相關文章