梦魇java_[Java教程]魔鬼的梦魇—验证IE中的JS内存泄露模式(一)
[Java教程]魔鬼的梦魇—验证IE中的JS内存泄露模式(一)
0 2012-05-08 07:00:04
随着移动互联网的发展,现在越来越多的应用开始想bs方向转移,原来很多复杂的计算逻辑也自然随着转移到了客户端,需要客户端的javascript来担任实现的角色;原本不起眼的内存泄露,现在却犹如恶魔会很快的吞噬掉用户的内存。从去年开始就在专注js面向对象开发实现、托管代码垃圾回收算法、js内存泄露相关的东西;如果大家关注过这方面的东西,那我想你一定读过微软开发人员Justin Rogers撰写的那篇经典的内存泄露模式,其实道理阐述的很清楚,但是怎么证明和呈现泄露的存在呢?这是一直困扰我的一个难题!今天我们针对这篇文章的各个模式,记录一下自己的一些想法,很多是自己的推论,并不一定正确,欢迎大家批评指正;
泄露的客观因素
在过去,对于web开发人员内存泄露并没有引起大的问题,主要是因为页面都相对比较简单,并且页面也只是在一个站点内跳转(这也是一种很好的释放松散内存的方式);如果有内存泄露的话,那也是小的不足以引起开发人员的注意。
随着技术的发展,新的应用程序需要遵循更高的标准。一个页面或许会运行数个小时而没有跳转页面并通过web服务动态检索数据进行更新。复杂的事件机制、面向对象开发、闭包等很多语言特性被用来开发整个应用程序。在这些和其他的一些改变下,某些内存泄露模式开始变得更加突出,尤其是那些以前被页面跳转隐藏的泄露问题。
内存泄露模式
接下来我们将会讨论内存泄露模式,并且每个模式都会给出一些简单的例子。现在,我们简单的看一下以下的模式:
1. 循环引用---当IE中COM对象和js的对象形成循环引用的时候,对象得不到释放就是造成内存泄露。这是一种最广泛的模式。
2. 闭包---作为一种在web应用程序中使用最广泛的模式,闭包是以一种特殊方式的循环引用造成内存泄露的。
3. 跨页泄露---当你从一个页面跳转到另一个页面的时候,由于产生的一些中间对象会形成很微弱的内存泄露。
4. Pseudo-Leaks---这个并不是真正的泄露,但是如果你不理解这个,那么你的内存不断增加也是十分恼人的。
以上是根据自己对文章的理解,对部分文字的翻译,下面我们将以同样的方式,先就翻译,然后记录相应的思考。
循环引用模式
循环引用几乎是所有泄露的根源。正常情况下,js的脚本引擎是可以通过垃圾回收器解
决循环引用问题的(js的垃圾回收器使用的标记擦除法,前面已经介绍过标记擦除法,这种算法本身是可以解决循环引用的问题),但是某些未知的情况会阻止其正常工作。在IE中这些未知情况出现在js对象可以访问DOM元素的情况下。其基本的规则原理如下图(循环引用模式原理图)所示
该模式导致内存泄露的原因是基于COM的引用计数器。Js引擎引用一个DOM元素,那么回收和释放DOM元素的引用,只能一直等待到对其引用被解除。在我们的图中,js引擎存在两个引用:scope对象和DOM元素的expando属性。当js引擎结束的时候将会释放第一个引用,但是对DOM元素的引用并不会释放,因为它会一直等待js引擎释放对它的引用。你或许会想很容易就可以探测到这种情况并解决这个问题,但是在实践中这只是众多情况中的冰山一角。如果循环引用是由30个对象的环(类似链表)形成的,那么将会很难探测到。
图 1. 循环引用模式原理图
根据这个原理图,我写了个测试的例子,在函数principlePictureLeak中,我们获取到span元素,并使obj1指向它,然后实例化对象obj4,并使span元素的expando属性指向obj4,具体的代码如下
View Code
在内存泄露检测工具sIEve中运行以上代码,我们可以看到并没有内存泄露,具体信息详见 下图(循环引用原理图内存泄露检测图)
图 2. 循环引用原理图内存泄露检测图
那么为什么没有形成内存泄露呢?按照Justin Rogers对循环引用模式原理的解释,上边的图1并没有完全展示出其描述的对象关联关系,那么我们可以看一下这些对象之间的关系(如图3),从图中我们可以看到对象图中并没有形成真正的”圆环”,自然也就没有形成真的循环引用,在函数执行完以后,js引擎就会释放对方法scope对象的引用,然后scope对象就会释放对obj1、obj4的引用,然后obj1就会释放对DOM元素的引用;那么这个时候如果执行完函数后,obj4是否会释放内存呢?
图 3. 循环引用模式原理图的对象关系
那么我们先来看以下的代码测试,其意图就是在setReference里使span元素引用一个js的对象,然后在getReference里来获取这个对象并输出其属性msg的值,经测试其最终输出了“DOM引用了js对象”,那么我们可以知道,DOM应用的局部变量并不会因为函数执行完毕而被回收掉。
View Code var DOMReleaseReferenceTestor = {
//span元素id
spanTagId: 'principlePictureSpan'
,
//设置span元素引用js的字符串
setReference: function () {
document.getElementById(DOMReleaseReferenceTestor.spanTagId).obj ={msg : 'DOM引用了js对象'};
}
,
//获取设置的span元素的字符串
getReference: function () {
alert(document.getElementById(DOMReleaseReferenceTestor.spanTagId).obj.msg);
}
,
//初始化
init: function () {
window.attachEvent("onload", DOMReleaseReferenceTestor.getReference);
window.attachEvent("onload", DOMReleaseReferenceTestor.setReference);
}
};
通过以上的代码测试,principlePictureLeak执行完成后,并没有回收obj4对象,但是当我们在sIEve中重复刷新页面并没有泄露,那么也就证明了,在刷新页面的时候,js脚本引擎解除了对DOM的引用,当DOM被回收后,就会释放对obj4的引用,从而成功的回收obj4。
以下是Justin Rogers针对循环引用模式给出的一个例子,代码如下
View Code html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
// First set up the script scope to element reference
myGlobalObject = document.getElementById("LeakedDiv"); // Next set up the element to script scope reference
document.getElementById("LeakedDiv").expandoProperty = myGlobalObject;
}
function BreakLeak() {
document.getElementById("LeakedDiv").expandoProperty =null;
}
我们可以简单的看以下各对象之间的引用关系(如图4),从图中我们可以看到myGlobalObject和LeakedDiv之间形成了循环引用的”环路”,这个在理论上构成了内存泄露的条件,那么到底有没有泄露呢,让我们使用sIEve来测试一下吧。
图 4. 循环引用例子1对象关系图
测试结果如下图(图5),让我们跌破眼睛的事情发生了,我们期盼已久的内存泄露并没有出现。那么这又是什么原因呢?那么下边我们看一下我这个可以出现内存泄露的代码例子。从代码中我们可以看到唯一不同的地方,就是我们新增的DOM元素,而不是直接使用的页面中的DOM元素。
View Code html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
var myGlobalObject;
var CircularReferencesTester = {
leak: function () {
this._leak(true);
}
,
unLeak:function(){
this._leak(false);
}
,
_leak:function(leak){
myGlobalObject = document.createElement("
if (leak) {
myGlobalObject.expandoProperty = myGlobalObject;
}
}
}; CircularReferencesTester.leak();
图 5. 循环引用例子泄露测试结果
先来看一下sIEve的测试结果吧,如图6,从图中我们可以看到,随着页面的刷新,内存泄露的数目不断增加,通过对比,我们可以知道循环引用模式产生内存泄露除了满足循环引用外,其中的DOM是动态新增的,而不是页面原有的DOM!
图 6. 我的循环引用例子泄露测试结果
最后总结一下,循环引用模式产生内存泄露除了满足循环引用外,其中的DOM是动态新增的,而不是页面原有的DOM!测试环境window 7 + IE 8。 本文网址:http://www.shaoqun.com/a/29495.html
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们:admin@shaoqun.com。
JS
0
梦魇java_[Java教程]魔鬼的梦魇—验证IE中的JS内存泄露模式(一)相关推荐
- 魔鬼的梦魇—验证IE中的js内存泄露模式(三)
魔鬼的梦魇-验证IE中的js内存泄露模式(三) 按照Justin Rogers文章的顺序,接下来的这个模式应该是跨页内存泄露模式(cross-page leak),但是由于这个模式产生的中间对象,我们 ...
- java知识点8——垃圾回收原理和算法、通用的分代垃圾回收机制、 JVM调优和Full GC、开发中容易造成内存泄露的操作
垃圾回收原理和算法 内存管理 Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new关键字创建对象即可 对象空间的释放:将对象赋值null即可 垃圾回 ...
- Python绘图之matplotlib基础教程:matplotlib库图表绘制中常规设置大全(交互模式、清除原有图像、设置横坐标显示文字/旋转角度、添加图例、绘图布局自动调整、图像显示、图像暂停)
Python绘图之matplotlib基础教程:matplotlib库图表绘制中常规设置大全(交互模式.清除原有图像.设置横坐标显示文字/旋转角度.添加图例.绘图布局自动调整.图像显示.图像暂停) 目 ...
- extjs form java_[Java教程]ExtJS入门教程02,form也可以很优雅
[Java教程]ExtJS入门教程02,form也可以很优雅 0 2014-03-28 12:00:40 在上一篇<Extjs window 入门>中,我们已经看到了如何将一个form组件 ...
- jquery 图片裁剪 java_[Java教程]5 款最新的 jQuery 图片裁剪插件
[Java教程]5 款最新的 jQuery 图片裁剪插件 0 2015-05-18 16:00:20 这篇文章主要介绍最新的 5 款 jQuery 图片裁剪插件,可以帮助你轻松的实现你网站需要的图像裁 ...
- return true Java_[Java教程]js中return,return true,return false的用法及区别
[Java教程]js中return,return true,return false的用法及区别 0 2015-11-16 23:00:03 1.语法及返回方式 ①返回控制与函数结果 语法为:retu ...
- 下拉加载 实现 java_[Java教程]iscroll5实现一个下拉刷新上拉加载的效果
[Java教程]iscroll5实现一个下拉刷新上拉加载的效果 0 2016-08-24 15:00:08 直接上代码!!! * { margin: 0; padding: 0; } ul, li { ...
- typescript 接口 java_[Java教程]【TypeScript】TypeScript 学习 2——接口
[Java教程][TypeScript]TypeScript 学习 2--接口 0 2015-06-19 12:00:28 在 TypeScript 中,接口是用作约束作用的,在编译成 JavaScr ...
- 前端开始学java_[Java教程]开启前端学习之路
[Java教程]开启前端学习之路 0 2014-06-10 17:00:06 前言 第一次在博客园写博客,写写自己开启前端学习之路.应该是受邢师兄的影响吧,不得不说邢师兄人很好,学习也很认真,师兄的前 ...
最新文章
- Fundamental Research:根系分泌物通过调控土壤微生物影响碳周转的机理
- 大型监控网络系统如何规划ip地址?
- 计算机视觉如何给企业带来不同?
- spring学习(39):注入map类型
- 串口硬盘如何应用于并口硬盘计算机,并口硬盘和串口硬盘如何一起用
- matlab求线性规划最大值,matlab线性规划算例
- TensorFlow调整超参数步骤
- Admob激励视频广告(rewarded ad)的服务器端验证(server-side )的疑问
- python实现12306自助刷票下单
- centeros域名解析失败
- 如何在小程序中直接跳到关注微信公众号页面
- 集成创新,拓展兼容--红旗Linux桌面版5.0隆重发布(转)
- Apache Mahout之协同过滤原理与实践(基于用户)
- mysql 除法和四舍五入
- undefined is not a function
- promise和async用法及区别(详解)
- android 微信图片选择,Android之仿微信图片选择器
- 去掉图片上的文字的几个基本技巧
- 通过开源的webdav-aliyundriver+Rclone挂载阿里云盘到服务器
- SF Symbols 2在哪里下载 (SwiftUI 教程)