JS造成内存泄漏的几种情况实例分析
本文实例讲述了JS造成内存泄漏的几种情况。分享给大家供大家参考,具体如下:
介绍:
js中的内存垃圾回收机制:垃圾回收器会定期扫描内存,当某个内存中的值被引用为零时就会将其回收。当前变量已经使用完毕但依然被引用,导致垃圾回收器无法回收这就造成了内存泄漏。传统页面每次跳转都会释放内存,所以并不是特别明显。
Vue单页面应用中:WebApp与传统Web的区别,因为WebApp是单页面应用页面通过路由跳转不会刷新页面,导致内存泄漏不断堆积,导致页面卡顿。
泄漏点:
1.DOM/BOM对象泄漏
2.script中存在对DOM/BOM对象的引用导致
3.Javascript对象泄漏
4.通常由闭包导致,比如事件处理回调,导致DOM对象和脚本中对象双向引用,这个时常见的泄漏原因
代码关注点:
1.DOM中的addEventLisner函数及派生的事件监听,比如Jquery中的on函数,vue组件实例的$on函数,第三方库中的初始化函数
2.其它BOM对象的事件监听,比如websocket实例的on函数
3.避免不必要的函数引用
4.如果使用render函数,避免在html标签中绑定DOM/BOM事件
Vue如何处理:
1.如果在mounted/created钩子中绑定了DOM/BOM对象中的事件,需要在beforeDestroy中做对应解绑处理
2.如果在mounted/created钩子中使用了第三方库初始化,需要在beforeDestroy中做对应销毁处理
3.如果组件中使用了定时器,需要在beforeDestroy中做对应销毁处理
4.模板中不要使用表达式来绑定到特定的处理函数,这个逻辑应该放在处理函数中?
5.如果在mounted/created钩子中使用了$on,需要在beforeDestroy中做对应解绑($off)处理
6.某些组件在模板中使用事件绑定可能会出现泄漏,使用$on替换模板中的绑定
Vue官网讲解避免内存泄露https://cn.vuejs.org/v2/cookbook/avoiding-memory-leaks.html
另外,vue 在IEedge浏览器下,父子组件的场景,子组件依赖父组件的状态,子组件控制父组件状态变化从而反馈给子组件的展示变化,子组件通过v-if模式存在于视图中,父组件通过状态控制子组件的v-if状态变换。子组件控制父组件状态完成子组件数据填充后,父组件切换子组件的v-if状态,子组件占用dom结构被清理。此时,子组件存在时的内存占用未被释放,当父组件再次回切v-if状态时,子组件重新展示,内存飙升,重复几次切换后,内存飙升明显,页面卡顿。
js通常内存泄漏的几种情况的介绍
1.闭包
functionfn1(){ varn=1; } //我想取到里面的局部变量n functionfn1(){ varn=1; functionfn2(){//在加一个fn2当他的子集 alert(n); } }
但是我在外面还是访问不到那就return出来
functionfn1(){ varn=1; functionfn2(){//在加一个fn2当他的子集 alert(n); } returnfn2(); //return出来后他就给window了所以一直存在内存中。因为一直在内存中,在IE里容易造成内存泄漏 } fn1();
尽量书写的时候,避免这种情况。
2.意外的全局变量
一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是window,也就是说:
functionfoo(arg){ bar="aaaaa"; } 实际上等价于 functionfoo(arg){ window.bar="aaaaa"; }
functionfoo(){ this.variable="qqqqq"; } //this指向全局对象(window) foo();
为了防止这种错误的发生,可以在你的JavaScript文件开头添加 'usestrict'; 语句
3.定时器setTimeoutsetInterval
当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。比如:vue使用了定时器,需要在beforeDestroy中做对应销毁处理。js也是一样的。
clearTimeout(***) clearInterval(***)
4.如果在mounted/created钩子中使用了$on,需要在beforeDestroy中做对应解绑($off)处理
beforeDestroy(){ this.bus.$off('****'); }
5、给DOM对象添加的属性是一个对象的引用
vartestObject={}; document.getElementById('idname').property=testObject;//如果DOM不被消除,则testObject会一直存在,造成内存泄漏
解决方法:
在window.onunload事件中写上:
window.onunload=function(){ document.getElementById('idname').property=null; //释放内存 };
6.DOM对象与JS对象相互引用
functiontestObject(element){ this.elementReference=element; //为testObject(js)对象的属性绑定element(DOM)对象 element.property=this; //为element(DOM)对象的属性绑定testObject(js)对象 } newtestObject(document.getElementById('idname'));
解决方法:
在window.onunload事件中写上:
document.getElementById('idname').property=null;
7.从外到内执行appendChild。这时即使调用removeChild也无法释放
varparentDiv=document.createElement("div"); varchildDiv=document.createElement("div"); document.body.appendChild(parentDiv); parentDiv.appendChild(childDiv);
解决方法:
从内到外执行appendChild:
varparentDiv=document.createElement("div"); varchildDiv=document.createElement("div"); parentDiv.appendChild(childDiv); document.body.appendChild(parentDiv);
8.反复重写同一个属性会造成内存大量占用(但关闭IE后内存会被释放)
for(i=0;i<5000;i++){ hostElement.text="asdfasdfasdf"; }
这种方式相当于定义了5000个属性!
9.注意程序逻辑,避免“死循环”之类的
10.echarts配合循环计时器等出现的内存泄漏
感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。
更多关于JavaScript相关内容可查看本站专题:《JavaScript操作DOM技巧总结》、《JavaScript页面元素操作技巧总结》、《JavaScript事件相关操作与技巧大全》、《JavaScript查找算法技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript错误与调试技巧总结》
希望本文所述对大家JavaScript程序设计有所帮助。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。