一次內存泄露排查

項目背景

後臺在管理界面直接編輯js,然後前端直接運行加載此 js,並且此頁面不會刷新(指定的 F5 這種刷新),而且是一直投影在屏幕上的。其中 js 分2部分,一部分是相對固定。一部分是動態的。前端通用不停的獲取後臺的 js 然後在實例化 js 來動態更新界面數據。

方案

直接使用 new Function 來動態解析後臺填寫的 js 腳本。demo 如下

<html>
    <head>
        <h1></h1>

    </head>
    <script>
        //轉換函數
        var convertToFn = function (fun) {
            return (new Function("return " + fun))();
        }
        var i = 0;
        setInterval(function(){
            var fn = convertToFn("{\
                            thisMap : {\
                                thisFn : function(){\
                                    return 'aaa'\
                                }\
                            }\
                        }");
            fn.thisMap.thisFn();
            i++;
            document.getElementsByTagName("h1")[0].innerHTML = i;
//            console.log(fn.thisMap.thisFn())
        }, 10);
    </script>
</html>

項目上線後發現此方法非常損耗內存。上面的函數循環大約20000次之後佔用內存 11MB 左右。並且一直不會釋放。從而導致瀏覽器內存耗盡奔潰。下圖有快照。

20000次很快就花完的了,而且設置的是4秒一次。又不止一個圖形在刷,有20+個。

曲線救國

不在支持動態刷新固定的部分的 js,只做值的動態更新。進一步驗證之後,此方式是可以有效控制內存不增長。demo 如下

<html>
    <head>
        <h1></h1>
    </head>
    <script>
        //先使用 el 表達式輸出到界面(或者使用 document.write 輸出,再不濟就用上面的 new Function 吧,只輸出一次就好 )
        var data = {};

        var fn = function(){
            return {
                thisMap : {
                    thisFn : function(){
                        return 'aaa'
                    },
                    getData : data
                }
            }
        }

        var i = 0;
        setInterval(function(){
            //賦值給此變量,後面調用的時候就可以拿到最新的了
            data = Math.random(1000000)*100;
            i++;
            document.getElementsByTagName("h1")[0].innerHTML = i;
//            console.log(fn().thisMap.getData)
        }, 10);
    </script>
</html>

下圖爲內存快照,開始有增長,後面基本就沒有了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章