JavaScript內存管理

內存管理.png

垃圾回收

垃圾回收:在不須要字符串、對象的時候,須要釋放其所佔用的內存。

高級語言解釋器嵌入了「垃圾回收器」,監控着全部對象,當對象生存週期結束時會將其刪除。
內嵌的垃圾回收器的問題:自動尋找是否一些內存「再也不須要」的問題是沒法斷定的。垃圾回收實現只能有限制的解決通常問題。因此引出垃圾回收算法(機制)。node

垃圾回收算法

垃圾回收算法主要依賴於引用的概念。在內存管理的環境中,一個對象若是有訪問另外一個對象的權限(隱式或者顯式),叫作一個對象引用另外一個對象。例如,一個Javascript對象具備對它原型的引用(隱式引用)和對它屬性的引用(顯式引用)。算法

在這裏,「對象」的概念不只特指 JavaScript 對象,還包括函數做用域(或者全局詞法做用域)。segmentfault

垃圾回收算法的原理:垃圾收集器會按照固定的時間間隔,週期性的找出再也不繼續使用的變量,而後釋放其佔用的內存。
再也不使用的變量也就是生命週期結束的變量,是局部變量,局部變量只在函數的執行過程當中存在,當函數運行結束,沒有其餘引用(閉包),那麼該變量會被標記回收。全局變量不會被當成垃圾回收。數組

「標記-清除算法」

工做原理:
當變量進入環境時(例如在函數中聲明一個變量),將這個變量標記爲「進入環境」,當變量離開環境時,則將其標記爲「離開環境」。標記「離開環境」的就回收內存。瀏覽器

工做流程:閉包

  1. 垃圾收集器會在運行的時候會給存儲在內存中的全部變量都加上標記。
  2. 去掉環境中的變量以及被環境中的變量引用的變量的標記。
  3. 那些還存在標記的變量被視爲準備刪除的變量。
  4. 最後垃圾收集器會執行最後一步內存清除的工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。
引用計數算法:被廢棄的垃圾收集策略

內存泄露

內存泄漏:未能釋放再也不使用的內存,形成內存的浪費。
  • 即便是1byte的內存,也叫內存泄漏,並不必定是致使瀏覽器崩潰、卡頓才能叫作內存泄漏。
  • 通常是堆區內存泄漏,棧區不會泄漏。
  • 基本類型的值存在內存中,被保存在棧內存中,引用類型的值是對象,保存在堆內存中。因此對象、數組之類的,纔會發生內存泄漏。

哪些狀況會引發內存泄漏?

雖然有垃圾回收機制,但咱們在編寫代碼的時候,有些狀況仍是會形成內存泄漏,瞭解這些狀況,並在編寫程序的時候,注意避免,咱們的程序會更具健壯性。dom

意外的全局變量:

全局變量不會被當成垃圾回收,咱們在編碼中有時會出現下面這種狀況:函數

function foo() {
     this.bar2 = '默認綁定this指向全局' // 全局變量=> window.bar2
      bar = '全局變量'; // 沒有聲明變量 其實是全局變量=>window.bar
    }
    foo();

當咱們使用默認綁定,this會指向全局,this.something也會建立一個全局變量,這一點可能不少人沒有注意到。this

解決方法:
1. 在函數內使用嚴格模式編碼

function foo() {
      "use strict"; 
      this.bar2 = "嚴格模式下this指向undefined"; 
      bar = "報錯";
    }
    foo();

2.手動釋放全局變量的內存

window.bar = undefined
    delete window.bar2
被遺忘的定時器和回調函數

不須要setInterval或者setTimeout時,定時器沒有被clear,定時器的回調函數以及內部依賴的變量都不能被回收,形成內存泄漏。

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        node.innerHTML = JSON.stringify(someResource));
        // 定時器也沒有清除
    }
    // node、someResource 存儲了大量數據 沒法回收
}, 1000);

解決方法: 在定時器完成工做的時候,手動清除定時器。

閉包:

閉包能夠維持函數內局部變量,使其得不到釋放,形成內存泄漏

function bindEvent() {
      var obj = document.createElement("XXX");
      var unused = function () {
          console.log(obj,'閉包內引用obj obj不會被釋放');
      };
      // obj = null;
    }

解決方法:手動解除引用,obj = null

沒有清理DOM元素引用:
var refA = document.getElementById('refA');
    document.body.removeChild(refA); // dom刪除了
    console.log(refA, "refA");  // 可是還存在引用 能console出整個div 沒有被回收

不信的話,能夠看下這個dom點擊預覽。

解決辦法:refA = null;

console保存大量數據在內存中。

過多的console,好比定時器的console會致使瀏覽器卡死。

解決辦法:合理利用console,線上項目儘可能少的使用console。


參考文章:https://segmentfault.com/a/11...
參考文章:https://segmentfault.com/a/11...

相關文章
相關標籤/搜索