一文理清由閉包引起內存泄漏和垃圾回收機制

閉包

  • 閉包的定義:當內部的函數被保存到外部時,將會生成閉包,閉包會致使原有的做用域鏈不釋放,形成內存泄漏。
  • 閉包的好處:
    • 變量長期駐紮在內存中
    • 避免污染全局變量
    • 私有成員的存在
  • 閉包的壞處:
    • 增大內存的使用量
    • 容易形成內存泄漏
  • 閉包的做用/使用場景
    • 實現共有變量 =》 作累加器
      • 代碼實現
        function add() {
            var count = 0;
            function demo() {
                count ++;
                console.log(count);
            }
            return demo;
        }
        var counter = add();
        counter();
        counter();
        複製代碼
    • 能夠作緩存
      • 代碼實現
        function eater() {
            var food = '';
            var obj = {
                eat: function() {
                    console.log('i am eating' + ' ' + food);
                    food = '';
                },
                push: function(myFood) {
                    food = myFood;
                }
            }
        }
        var eater1 = eater();
        eater.push('banana');
        eater.eater();
        複製代碼
    • 能夠實現封裝 屬性私有化
      • 代碼實現
        function Hang(name, wife) {
            var prepareWife = 'xiaozhang';
            this.name = name;
            this.wife = wife;
            this.divorce = function() {
                this.wife = prepareWife;
            }
            this.changePrepareWife = function(target) {
                prepareWife = target;
            }
            this.sayPrepareWife = function() {
                console.log(prepareWife);
            }
        }
        var deng = new Hang('deng', 'xiaoliu');
        deng.prepareWife;
        deng.sayPrepareWife();
        複製代碼
  • 閉包的防護
    • 閉包會致使多個執行函數共用一個公有變量,若是不是特殊須要,應該儘可能防止這種狀況發生。
  • 解決閉包的方法
    • 使用當即執行函數

當即執行函數

  • 當即執行函數定義:此類函數沒有聲明,在一次執行事後釋放,適合作初始化工做。
  • 當即執行函數和普通函數的區別:當即執行函數執行完就被釋放

內存泄漏

  • 內存泄漏定義:應用程序再也不須要佔用的時候,因爲某些緣由,內存沒有被操做系統或可用內存池回收。
  • 內存泄漏的例子:
    • 意外的全局變量
      • 在函數內未聲明的變量就賦值,這樣會在全局對象建立一個新的變量。
        function bar() {
            say = 'hehe';
        }
        
        即==
        function bar() {
            window.say ='hehe';
        }
        複製代碼
      • 或者是使用this建立了全局的變量
        function foo() {
            this.name = 'hehe';
        }
        foo();
        複製代碼
    • 被遺忘的計時器或回調函數
      • 使用計時器setInterval()未清除,在老版本的IE6是沒法處理循環引用的,會形成內存泄漏。
    • 脫離DOM的引用的
    • 閉包
  • 如何識別的內存泄漏
    • Chrome
      • Timeline
      • Profiles
    • Node
  • 怎麼解決
    • 手動釋放
      • 代碼實現
        var arr = [1, 2, 3];
        arr = null;
        複製代碼
    • 使用弱引用(weakset和weakmap)
      • 優勢:WeakMap裏面對element的引用就是弱引用,不會被計入垃圾回收機制的。也就是說一旦消除對該節點的引用,它的佔用內存就會被垃圾回收機制釋放。WeakMap保存的這個鍵值對,也會自動消失。
      • 代碼實現
        const vm = new WeakMap();
        const element = document.getElementById('example');
        vm.set(element, 'something');
        vm.get(element);
        複製代碼

垃圾回收機制

  • 定義:大多數語言提供自動內存管理,減輕程序員的負擔,這就被稱爲"垃圾回收機制"。
  • 經常使用的垃圾回收算法
    • 引用計數法
      • 優勢:
        • 可即刻回收:當被引用數值爲0,對象立刻會把本身做爲空閒空間連到空閒鏈表上。也就是說,在變成垃圾的時候就馬上被回收。
        • 由於是即便回收,那麼程序不會暫停去單獨使用很長一段時間的GC,那麼最大暫停時間很短。
        • 不用去遍歷堆裏面的全部活動對象和非活動對象。
      • 缺點:
        • 計數器須要佔很大的位置:由於不能預估被引用的上限,打個比方,可能出現32位即2的32次方個對象同時引用一個對象,那麼計時器就須要32位。
        • 最大的劣勢是沒法解決循環引用沒法回收的問題,這就是IE以前出現的問題。
      • 代碼示例
        var a = new Object();
        var b = a;
        a = null;
        b = null;
        複製代碼
    • 標記清除法(在V8引擎使用最多的)
      • 垃圾回收過程
        • 標記階段:把全部活動對象作上標記
        • 清除階段:把沒有標記(也就是說非活動對象)銷燬
      • 優點
        • 實現簡單,打標記用一位二進制就能夠表示
        • 解決了循環引用的問題
      • 缺點
        • 形成碎片化(有點相似磁盤的碎片化)
        • 再分配時遍歷次數多,若是一直沒有找到合適的內存塊大小,那麼會遍歷空閒鏈表(保存堆中全部空閒地址空間的地址造成的鏈表)一直遍歷到尾端。
    • 複製算法
      • 將一塊內存空間分爲兩部分,分別爲From空間和To空間。在這兩個空間中,一定有一個空間是使用的另外一個空間是空閒的,新分配的對象會被放入From空間中,當From空間被佔滿的時,新生代GC就會啓動了。算法就檢查From空間中存活的對象複製到To空間中,若是有失活的對象就會銷燬,當賦值完成後將From,空間和To空間互換,這樣GC就結束了。

你的點贊是我持續輸出的動力 但願能幫助到你們 互相學習 有任何問題下面留言 必定回覆

相關文章
相關標籤/搜索