一次内存泄露排查

项目背景

后台在管理界面直接编辑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>

下图为内存快照,开始有增长,后面基本就没有了

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