一次内存泄露排查
2018-05-29 本文已影响12人
JerryDai
项目背景
后台在管理界面直接编辑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 左右。并且一直不会释放。从而导致浏览器内存耗尽奔溃。下图有快照。
image20000次很快就花完的了,而且设置的是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>
下图为内存快照,开始有增长,后面基本就没有了
image