[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内存泄露模式(一)相关推荐

  1. 魔鬼的梦魇—验证IE中的js内存泄露模式(三)

    魔鬼的梦魇-验证IE中的js内存泄露模式(三) 按照Justin Rogers文章的顺序,接下来的这个模式应该是跨页内存泄露模式(cross-page leak),但是由于这个模式产生的中间对象,我们 ...

  2. java知识点8——垃圾回收原理和算法、通用的分代垃圾回收机制、 JVM调优和Full GC、开发中容易造成内存泄露的操作

    垃圾回收原理和算法 内存管理 Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new关键字创建对象即可 对象空间的释放:将对象赋值null即可 垃圾回 ...

  3. Python绘图之matplotlib基础教程:matplotlib库图表绘制中常规设置大全(交互模式、清除原有图像、设置横坐标显示文字/旋转角度、添加图例、绘图布局自动调整、图像显示、图像暂停)

    Python绘图之matplotlib基础教程:matplotlib库图表绘制中常规设置大全(交互模式.清除原有图像.设置横坐标显示文字/旋转角度.添加图例.绘图布局自动调整.图像显示.图像暂停) 目 ...

  4. extjs form java_[Java教程]ExtJS入门教程02,form也可以很优雅

    [Java教程]ExtJS入门教程02,form也可以很优雅 0 2014-03-28 12:00:40 在上一篇<Extjs window 入门>中,我们已经看到了如何将一个form组件 ...

  5. jquery 图片裁剪 java_[Java教程]5 款最新的 jQuery 图片裁剪插件

    [Java教程]5 款最新的 jQuery 图片裁剪插件 0 2015-05-18 16:00:20 这篇文章主要介绍最新的 5 款 jQuery 图片裁剪插件,可以帮助你轻松的实现你网站需要的图像裁 ...

  6. 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 ...

  7. 下拉加载 实现 java_[Java教程]iscroll5实现一个下拉刷新上拉加载的效果

    [Java教程]iscroll5实现一个下拉刷新上拉加载的效果 0 2016-08-24 15:00:08 直接上代码!!! * { margin: 0; padding: 0; } ul, li { ...

  8. typescript 接口 java_[Java教程]【TypeScript】TypeScript 学习 2——接口

    [Java教程][TypeScript]TypeScript 学习 2--接口 0 2015-06-19 12:00:28 在 TypeScript 中,接口是用作约束作用的,在编译成 JavaScr ...

  9. 前端开始学java_[Java教程]开启前端学习之路

    [Java教程]开启前端学习之路 0 2014-06-10 17:00:06 前言 第一次在博客园写博客,写写自己开启前端学习之路.应该是受邢师兄的影响吧,不得不说邢师兄人很好,学习也很认真,师兄的前 ...

最新文章

  1. Fundamental Research:根系分泌物通过调控土壤微生物影响碳周转的机理
  2. 大型监控网络系统如何规划ip地址?
  3. 计算机视觉如何给企业带来不同?
  4. spring学习(39):注入map类型
  5. 串口硬盘如何应用于并口硬盘计算机,并口硬盘和串口硬盘如何一起用
  6. matlab求线性规划最大值,matlab线性规划算例
  7. TensorFlow调整超参数步骤
  8. Admob激励视频广告(rewarded ad)的服务器端验证(server-side )的疑问
  9. python实现12306自助刷票下单
  10. centeros域名解析失败
  11. 如何在小程序中直接跳到关注微信公众号页面
  12. 集成创新,拓展兼容--红旗Linux桌面版5.0隆重发布(转)
  13. Apache Mahout之协同过滤原理与实践(基于用户)
  14. mysql 除法和四舍五入
  15. undefined is not a function
  16. promise和async用法及区别(详解)
  17. android 微信图片选择,Android之仿微信图片选择器
  18. 去掉图片上的文字的几个基本技巧
  19. 通过开源的webdav-aliyundriver+Rclone挂载阿里云盘到服务器
  20. SF Symbols 2在哪里下载 (SwiftUI 教程)

热门文章

  1. 前端网页三剑客------CSS基础
  2. 8.input子系统基础之按键
  3. Js fancybox做图片查看器
  4. 15行CSS代码 就可以让你的手机软重启
  5. 都8102年了,你为什么还在装系统?!
  6. 必须理解的计算机核心概念
  7. 草稿箱测试111-23
  8. canal部署、原理和使用介绍
  9. 本地AC在线WA?RE?来个栗子帮助你。
  10. [转帖]全方位掌握OpenStack技术知识