複習Javascript專題(二):閉包,內存,以及垃圾回收機制

1.什麼是閉包?閉包有啥特性以及存在什麼問題?

概念:閉包是指有權訪問另外一個函數做用域中的變量的函數。下面的outer就造成了一個閉包:
function outer(){
    const name='nagi';
    return function inner(){
        console.log(name);
    }
 }
let p=outer();
}
let p=outer();

通常來說,當函數執行完畢後,局部活動對象就會被銷燬,內存中僅保存全局執行環境中的變量對象,但閉包有所不一樣。
當outer()執行完後,由於inner函數的做用域鏈在引用outer的活動對象,因此它並不會被銷燬,而是仍然留在內存中,
除非inner函數也銷燬它的活動對象纔會被銷燬。好比使p=null;git

特性: 由上面的代碼能夠得出如下幾個特性:github

a. 函數嵌套函數,做爲一個函數變量的一個引用,當函數返回時,其處於激活狀態。
b. 函數內部能夠引用外部的參數和變量。
c. 一個閉包就是當一個函數返回時,一個沒有釋放資源的棧區,因此參數和變量不會被垃圾回收機制回收。

優勢:閉包

a. 減小全局變量的污染
 b. 能夠有私有變量的存在
function counter(){
    let n=0;
    function add(){
        n++;
       console.log(n);
    }
    return {n:n, add:add}
}
const c1=counter();
const c2=counter(); // 它和c1分別存入了不一樣的堆內存中
c1.add(); // 1
c1.add(); // 2
c1.n;     // 0 // 此處的n是基本類型,除非從新賦值,不然不會變!
c2.add(); // 1 c1和c2互不干涉,都有本身的新的做用域鏈和新的私有變量
注意!!父函數每次調用會產生新的閉包

缺點(問題)函數

a.常駐內存,增長內存使用量。
b. 使用不當會很容易形成內存泄露。
另:閉包的多種寫法能夠參照這裏: JavaScript閉包(closure)

2.js中的垃圾回收機制

原理:js中有自動回收管理內存機制,它的原理是會按期(週期性地)找出那些再也不繼續使用的變量,而後釋放其佔用的內存。

內存管理:指針

1. 分配內存(無論是基本類型仍是引用類型)
2. 使用內存(對變量,函數等讀取或寫操做)
3. 釋放內存(使用垃圾回收機制回收內存)

回收方式

1.引用計數

**含義:**跟蹤記錄每一個值被引用的次數。
**工做機制:**
    當聲明一個變量並將一個引用類型值賦給它時,則這個值的引用次數就是1;
    若是同一個值又被賦給另外一個變量,則該值的引用次數加1;
    相反,若是包含對這個值引用的變量又被賦了其餘值,則這個值的引用次數減1;
    當這個值的引用次數爲0時,則說明沒有辦法再訪問這個值了;
    這樣,當垃圾收集器下次再運行時,便會釋放這種引用次數爲0的值所佔的內存。

問題:code

這種方式有一個嚴重的問題,即「循環引用」。
意思是對象A中包含一個指向對象B的指針,而對象B也包含一個指向對象A的指針,
這樣當函數執行完畢後,由於其引用也就永遠不會爲0,因此對象A和B將繼續存在,
若是對象所在函數被重複調用,就會致使大量內存得不到回收。
function problem(){
     let objA=new Object();
     let objB=new Object();

     objA.someOtherObj=objB;
     objB.antherObj=objA;
 }

2.標記清除(經常使用方式)

原理:垃圾回收器會在運行時給存儲在內存中的全部變量加一個標記。
(當變量進入環境時,就交這個變量標記爲「進入環境」。而當變量離開環境時,則將其標記爲「離開環境」。)

而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記(閉包)。

而在這些完成以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了。

最後,垃圾回收器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。
相關文章
相關標籤/搜索