1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        WeakMap 和 Map 的區(qū)別,WeakMap 原理,為什么能被 GC?

        共 4900字,需瀏覽 10分鐘

         ·

        2021-10-02 06:04

        面試官也在看的前端面試資料

        垃圾回收機(jī)制

        我們知道,程序運(yùn)行中會有一些垃圾數(shù)據(jù)不再使用,需要及時釋放出去,如果我們沒有及時釋放,這就是內(nèi)存泄露

        JS 中的垃圾數(shù)據(jù)都是由垃圾回收(Garbage Collection,縮寫為 GC)器自動回收的,不需要手動釋放,它是如何做的喃?

        很簡單,JS 引擎中有一個后臺進(jìn)程稱為垃圾回收器,它監(jiān)視所有對象,觀察對象是否可被訪問,然后按照固定的時間間隔周期性的刪除掉那些不可訪問的對象即可

        現(xiàn)在各大瀏覽器通常用采用的垃圾回收有兩種方法:

        • 引用計數(shù)
        • 標(biāo)記清除

        引用計數(shù)

        最早最簡單的垃圾回收機(jī)制,就是給一個占用物理空間的對象附加一個引用計數(shù)器,當(dāng)有其它對象引用這個對象時,這個對象的引用計數(shù)加一,反之解除時就減一,當(dāng)該對象引用計數(shù)為 0 時就會被回收。

        該方式很簡單,但會引起內(nèi)存泄漏:

        // 循環(huán)引用的問題
        function temp(){
            var a={};
            var b={};
            a.o = b;
            b.o = a;
        }

        這種情況下每次調(diào)用 temp 函數(shù),ab 的引用計數(shù)都是 2 ,會使這部分內(nèi)存永遠(yuǎn)不會被釋放,即內(nèi)存泄漏?,F(xiàn)在已經(jīng)很少使用了,只有低版本的 IE 使用這種方式。

        標(biāo)記清除

        V8 中主垃圾回收器就采用標(biāo)記清除法進(jìn)行垃圾回收。主要流程如下:

        • 標(biāo)記:遍歷調(diào)用棧,看老生代區(qū)域堆中的對象是否被引用,被引用的對象標(biāo)記為活動對象,沒有被引用的對象(待清理)標(biāo)記為垃圾數(shù)據(jù)。
        • 垃圾清理:將所有垃圾數(shù)據(jù)清理掉

        (圖片來源:How JavaScript works: memory management + how to handle 4 common memory leaks)

        在我們的開發(fā)過程中,如果我們想要讓垃圾回收器回收某一對象,就將對象的引用直接設(shè)置為 null

        var a = {}; // {} 可訪問,a 是其引用

        a = null// 引用設(shè)置為 null
        // {} 將會被從內(nèi)存里清理出去

        但如果一個對象被多次引用時,例如作為另一對象的鍵、值或子元素時,將該對象引用設(shè)置為 null 時,該對象是不會被回收的,依然存在

        var a = {}; 
        var arr = [a];

        a = null
        console.log(arr)
        // [{}]

        如果作為 Map 的鍵喃?

        var a = {}; 
        var map = new Map();
        map.set(a, '三分鐘學(xué)前端')

        a = null
        console.log(map.keys()) // MapIterator {{}}
        console.log(map.values()) // MapIterator {"三分鐘學(xué)前端"}

        如果想讓 a 置為 null 時,該對象被回收,該怎么做喃?

        WeakMap vs Map

        ES6 考慮到了這一點(diǎn),推出了:WeakMap 。它對于值的引用都是不計入垃圾回收機(jī)制的,所以名字里面才會有一個"Weak",表示這是弱引用(對對象的弱引用是指當(dāng)該對象應(yīng)該被GC回收時不會阻止GC的回收行為)。

        Map 相對于 WeakMap

        • Map 的鍵可以是任意類型,WeakMap 只接受對象作為鍵(null除外),不接受其他類型的值作為鍵
        • Map 的鍵實(shí)際上是跟內(nèi)存地址綁定的,只要內(nèi)存地址不一樣,就視為兩個鍵;WeakMap 的鍵是弱引用,鍵所指向的對象可以被垃圾回收,此時鍵是無效的
        • Map 可以被遍歷, WeakMap 不能被遍歷

        下面以 WeakMap 為例,看看它是怎么上面問題的:

        var a = {}; 
        var map = new WeakMap();
        map.set(a, '三分鐘學(xué)前端')
        map.get(a)

        a = null

        上例并不能看出什么?我們通過 process.memoryUsage 測試一下:

        //map.js
        global.gc(); // 0 每次查詢內(nèi)存都先執(zhí)行g(shù)c()再memoryUsage(),是為了確保垃圾回收,保證獲取的內(nèi)存使用狀態(tài)準(zhǔn)確

        function usedSize({
            const used = process.memoryUsage().heapUsed;
            return Math.round((used / 1024 / 1024) * 100) / 100 + "M";
        }

        console.log(usedSize()); // 1 初始狀態(tài),執(zhí)行g(shù)c()和memoryUsage()以后,heapUsed 值為 1.64M

        var map = new Map();
        var b = new Array(5 * 1024 * 1024);

        map.set(b, 1);

        global.gc();
        console.log(usedSize()); // 2 在 Map 中加入元素b,為一個 5*1024*1024 的數(shù)組后,heapUsed為41.82M左右

        b = null;
        global.gc();

        console.log(usedSize()); // 3 將b置為空以后,heapUsed 仍為41.82M,說明Map中的那個長度為5*1024*1024的數(shù)組依然存在

        執(zhí)行 node --expose-gc map.js 命令:

        其中,--expose-gc 參數(shù)表示允許手動執(zhí)行垃圾回收機(jī)制

        // weakmap.js
        function usedSize({
            const used = process.memoryUsage().heapUsed;
            return Math.round((used / 1024 / 1024) * 100) / 100 + "M";
        }

        global.gc(); // 0 每次查詢內(nèi)存都先執(zhí)行g(shù)c()再memoryUsage(),是為了確保垃圾回收,保證獲取的內(nèi)存使用狀態(tài)準(zhǔn)確
        console.log(usedSize()); // 1 初始狀態(tài),執(zhí)行g(shù)c()和 memoryUsage()以后,heapUsed 值為 1.64M
        var map = new WeakMap();
        var b = new Array(5 * 1024 * 1024);

        map.set(b, 1);

        global.gc();
        console.log(usedSize()); // 2 在 Map 中加入元素b,為一個 5*1024*1024 的數(shù)組后,heapUsed為41.82M左右

        b = null;
        global.gc();

        console.log(usedSize()); // 3 將b置為空以后,heapUsed 變成了1.82M左右,說明WeakMap中的那個長度為5*1024*1024的數(shù)組被銷毀了

        執(zhí)行 node --expose-gc weakmap.js 命令:

        上面代碼中,只要外部的引用消失,WeakMap 內(nèi)部的引用,就會自動被垃圾回收清除。由此可見,有了它的幫助,解決內(nèi)存泄漏就會簡單很多。

        最后看一下 WeakMap

        WeakMap

        WeakMap 對象是一組鍵值對的集合,其中的鍵是弱引用對象,而值可以是任意。

        注意,WeakMap 弱引用的只是鍵名,而不是鍵值。鍵值依然是正常引用。

        WeakMap 中,每個鍵對自己所引用對象的引用都是弱引用,在沒有其他引用和該鍵引用同一對象,這個對象將會被垃圾回收(相應(yīng)的key則變成無效的),所以,WeakMap 的 key 是不可枚舉的。

        屬性:

        • constructor:構(gòu)造函數(shù)

        方法:

        • has(key):判斷是否有 key 關(guān)聯(lián)對象
        • get(key):返回key關(guān)聯(lián)對象(沒有則則返回 undefined)
        • set(key):設(shè)置一組key關(guān)聯(lián)對象
        • delete(key):移除 key 的關(guān)聯(lián)對象
        let myElement = document.getElementById('logo');
        let myWeakmap = new WeakMap();

        myWeakmap.set(myElement, {timesClicked0});

        myElement.addEventListener('click'function({
          let logoData = myWeakmap.get(myElement);
          logoData.timesClicked++;
        }, false);

        除了 WeakMap 還有 WeakSet 都是弱引用,可以被垃圾回收機(jī)制回收,可以用來保存DOM節(jié)點(diǎn),不容易造成內(nèi)存泄漏

        另外還有 ES12 的 WeakRef ,感興趣的可以了解下,今晚太晚了,之后更新

        參考

        你不知道的 WeakMap

        來自:https://github.com/Advanced-Frontend/Daily-Interview-Question

        最后

        歡迎關(guān)注「三分鐘學(xué)前端」,回復(fù)「交流」自動加入前端三分鐘進(jìn)階群,每日一道編程算法題(第二天解答),助力你成為更優(yōu)秀的前端開發(fā)!

        》》面試官也在看的前端面試資料《《
        “在看和轉(zhuǎn)發(fā)”就是最大的支持
        瀏覽 27
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            91香蕉视频黄 | 亚洲国产日韩在线 | 理论片在线观看理伦片 | 成人免费视频 在线观看 | 精品视频久久 | 性感美女视频诱惑国产 | 被女同桌强行足脚交了 | 久久久久久国产精品频道 | 男人桶女人桶爽 | 7777AV |