js内存泄露的几种情况详细探讨
2023-06-13 09:15:00 时间
内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。在C++中,因为是手动管理内存,内存泄露是经常出现的事情。而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使用的情况下几乎不会发生内存泄露。浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。
1、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。
复制代码代码如下:
1、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。
<divid="myDiv">
<inputtype="button"value="Clickme"id="myBtn">
</div>
<scripttype="text/javascript">
varbtn=document.getElementById("myBtn");
btn.onclick=function(){
document.getElementById("myDiv").innerHTML="Processing...";
}
</script>
应改成下面
<divid="myDiv">
<inputtype="button"value="Clickme"id="myBtn">
</div>
<scripttype="text/javascript">
varbtn=document.getElementById("myBtn");
btn.onclick=function(){
btn.onclick=null;
document.getElementById("myDiv").innerHTML="Processing...";
}
</script>
或者采用事件委托
<divid="myDiv">
<inputtype="button"value="Clickme"id="myBtn">
</div>
<scripttype="text/javascript">
document.onclick=function(event){
event=event||window.event;
if(event.target.id=="myBtn"){
document.getElementById("myDiv").innerHTML="Processing...";
}
}
</script>
2、
vara=document.getElementById("#xx");
varb=document.getElementById("#xxx");
a.r=b;
b.r=a;
vara=document.getElementById("#xx");
a.r=a;
对于纯粹的ECMAScript对象而言,只要没有其他对象引用对象a、b,也就是说它们只是相互之间的引用,那么仍然会被垃圾收集系统识别并处理。但是,在InternetExplorer中,如果循环引用中的任何对象是DOM节点或者ActiveX对象,垃圾收集系统则不会发现它们之间的循环关系与系统中的其他对象是隔离的并释放它们。最终它们将被保留在内存中,直到浏览器关闭。
3、
varelem=document.getElementById("test");
elem.addEventListener("click",function(){
alert("Youclicked"+elem.tagName);
});
这段代码把一个匿名函数注册为一个DOM结点的click事件处理函数,函数内引用了一个DOM对象elem,就形成了闭包。这就会产生一个循环引用,即:DOM->闭包->DOM->闭包...DOM对象在闭包释放之前不会被释放;而闭包作为DOM对象的事件处理函数存在,所以在DOM对象释放前闭包不会释放,即使DOM对象在DOMtree中删除,由于这个循环引用的存在,DOM对象和闭包都不会被释放。可以用下面的方法可以避免这种内存泄露
varelem=document.getElementById("test");
elem.addEventListener("click",function(){
alert("Youclicked"+this.tagName);//不再直接引用elem变量
});
4、
functionbindEvent()
{
varobj=document.createElement("XXX");
obj.onclick=function(){
//Evenifit"saemptyfunction
}
}
闭包非常容易构成循环引用。如果一个构成闭包的函数对象被指定给,比如一个DOM节点的事件处理器,而对该节点的引用又被指定给函数对象作用域中的一个活动(或可变)对象,那么就存在一个循环引用。
DOM_Node.onevent-<function_object.[[scope]]-<scope_chain-<Activation_object.nodeRef-<DOM_Node。
形成这样一个循环引用是轻而易举的,而且稍微浏览一下包含类似循环引用代码的网站(通常会出现在网站的每个页面中),就会消耗大量(甚至全部)系统内存。
解决之道,将事件处理函数定义在外部,解除闭包
functionbindEvent()
{
varobj=document.createElement("XXX");
obj.onclick=onclickHandler;
}
functiononclickHandler(){
//dosomething
}
或者在定义事件处理函数的外部函数中,删除对dom的引用(题外,《JavaScript权威指南》中介绍过,闭包中,作用域中没用的属性可以删除,以减少内存消耗。)
functionbindEvent()
{
varobj=document.createElement("XXX");
obj.onclick=function(){
//Evenifit"saemptyfunction
}
obj=null;
}
5、
a={p:{x:1}};
b=a.p;
deletea.p;
执行这段代码之后b.x的值依然是1.由于已经删除的属性引用依然存在,因此在JavaScript的某些实现中,可能因为这种不严谨的代码而造成内存泄露。所以在销毁对象的时候,要遍历属性中属性,依次删除。
6.自动类型装箱转换
别不相信,下面的代码在ie系列中会导致内存泄露
vars=”lalala”;
alert(s.length);
s本身是一个string而非object,它没有length属性,所以当访问length时,JS引擎会自动创建一个临时String对象封装s,而这个对象一定会泄露。这个bug匪夷所思,所幸解决起来相当容易,记得所有值类型做.运算之前先显式转换一下:
vars="lalala";
alert(newString(s).length);
7、某些DOM操作
IE系列的特有问题简单的来说就是在向不在DOM树上的DOM元素appendChild;IE7中,貌似为了改善内存泄露,IE7采用了极端的解决方案:离开页面时回收所有DOM树上的元素,其它一概不管。
相关文章
- html如何只刷新页面指定,js控制页面刷新 JS刷新当前页面的几种方法总结
- 初识js中的闭包_Js闭包中变量理解
- 【说站】js中hasOwnProperty的属性用法
- 【说站】js原型链继承的缺点
- Js排序算法_js 排序算法
- Js生成二维码_js在线生成二维码
- 用 JS 编写自动化脚本,而不是 bash!
- [WP Code Highlight.js] Project
- js 数组去除重复数据-5 个提升你 JS 编码水平的实例
- js 数组去除重复数据-当WPS开始像支持VBA一样支持JS语言时,微软又该何去何从?
- 推荐一个检测 JS 内存泄漏的神器
- 【JS 逆向百例】猿人学系列 web 比赛第二题:js 混淆 - 动态 cookie,详细剖析
- JS模块化—CJS&AMD&CMD&ES6-前端面试知识点查漏补缺_2023-03-13
- 原生 JS 实现 HTML 转 Markdown ,html2md.js
- get两个js小技能——JS截取视频第一帧&图片转Base64
- 如何使用jscythe并通过Node.js的Inspector机制执行任意JS代码
- clipboard.js:最轻便的复制页面内容到剪切板的JS
- JS exec()方法:执行正则表达式匹配
- 使用JS技术实现Oracle数据库链接(js 链接 oracle)
- JS技术连接Oracle数据库实现数据交互(js连接oracle实例)
- JS将文件传输至MySQL数据库(.js传文件至mysql)
- [对联广告]JS脚本类
- 判定对象是否为window的js代码
- 远离JS灾难css灾难之js私有函数和css选择器作为容器
- js实现的仿新浪微博完美的时间组件升级版
- js获取坐标通过JS得到当前焦点(鼠标)的坐标属性
- js封装cookie操作的函数代码
- js动态创建标签示例代码
- node.js中的fs.utimesSync方法使用说明
- 原生js实现复制对象、扩展对象类似jquery中的extend()方法