JavaScript的内存释放问题详解


Posted in Javascript onJanuary 21, 2015

本文详细的讲解了JavaScript及IE浏览器对内存的管理和释放的时机和方法,希望对前端开发人员有所帮助。

一个内存释放的实例

<SCRIPT LANGUAGE="JavaScript">

<!--

strTest = "1";

for ( var i = 0; i < 25; i ++ )

{

strTest += strTest;

}

alert(strTest);

delete strTest;

CollectGarbage();

//-->

</SCRIPT>

CollectGarbage,是IE的一个特有属性,用于释放内存的,使用方法嘛应该是,将该变量或引用对象,设置为null或delete,然后在进行释放动作

在做CollectGarbage前,要必需清楚的两个必备条件:

引用- 一个对象在其生存的上下文环境之外,即会失效。
- 一个全局的对象在没有被执用(引用)的情况下,即会失效。

//---------------------------------------------------------

// JavaScript对象何时失效

//---------------------------------------------------------

function testObject() {

var _obj1 = new Object();

}

function testObject2() {

var _obj2 = new Object();

return _obj2;

}

// 示例1

testObject();

// 示例2

testObject2()

// 示例3

var obj3 = testObject2();

obj3 = null;

// 示例4

var obj4 = testObject2();

var arr = [obj4];

obj3 = null;

arr = [];

在这四个示例中:
- “示例1”在函数testObject()中构造了_obj1,但是在函数退出时,它就已经离开了函数的上下文环境,因此_obj1失效了;

- “示例2”中,testObject2()中也构造了一个对象_obj2并传出,因此对象有了“函数外”的上下文环境(和生存周期),然而由于函数的返回值没有被其它变量“持有”,因此_obj2也立即失效了;

- “示例3”中,testObject2()构造的_obj2被外部的变量obj3持用了,这时,直到“obj3=null”这行代码生效时,_obj2才会因为引用关系消失而失效。

- 与示例3相同的原因,“示例4”中的_obj2会在“arr=[]”这行代码之后才会失效。

但是,对象的“失效”并不等会“释放”。在JavaScript运行环境的内部,没有任何方式来确切地告诉用户“对象什么时候会释放”。这依赖于JavaScript的内存回收机制。——这种策略与.NET中的回收机制是类同的。

在前面的Excel操作示例代码中,对象的所有者,也就是"EXCEL.EXE"这个进程只能在“ActiveX Object实例的释放”之后才会发生。而文件的锁,以及操作系统的权限凭证是与进程相关的。因此如果对象仅是“失效”而不是“释放”,那么其它进程处理文件和引用操作系统的权限凭据时就会出问题。

——有些人说这是JavaScript或者COM机制的BUG。其实不是,这是OS、IE和JavaScript之间的一种复杂关系所导致的,而非独立的问题。

Microsoft公开了解决这种问题的策略:主动调用内存回收过程。

在(微软的)JScript中提供了一个CollectGarbage()过程(通常简称GC过程),GC过程用于清理当前IE中的“失效的对象失例”,也就是调用对象的析构过程。

在上例中调用GC过程的代码是:

//---------------------------------------------------------

// 处理ActiveX Object时,GC过程的标准调用方式

//---------------------------------------------------------

function writeXLS() {

//(略...)

excel.Quit();

excel = null;

setTimeout(CollectGarbage, 1);

}

第一行代码调用excel.Quit()方法来使得excel进程中止并退出,这时由于JavaScript环境执有excel对象实例,因此excel进程并不实际中止。

第二行代码使excel为null,以清除对象引用,从而使对象“失效”。然而由于对象仍旧在函数上下文环境中,因此如果直接调用GC过程,对象仍然不会被清理。

第三行代码使用setTimeout()来调用CollectGarbage函数,时间间隔设为'1',只是使得GC过程发生在writeXLS()函数执行完之后。这样excel对象就满足了“能被GC清理”的两个条件:没有引用和离开上下文环境。

GC过程的使用,在使用了ActiveX Object的JS环境中很有效。一些潜在的ActiveXObject包括XML、VML、OWC(Office Web Componet)、flash,甚至包括在JS中的VBArray。从这一点来看,ajax架构由于采用了XMLHTTP,并且同时要满足“不切换页面”的特性,因此在适当的时候主动调用GC过程,会得到更好的效率用UI体验。

事实上,即使使用GC过程,前面提到的excel问题仍然不会被完全解决。因为IE还缓存了权限凭据。使页的权限凭据被更新的唯一方法,只能是“切换到新的页面”,

因此事实上在前面提到的那个SPS项目中,我采用的方法并不是GC,而是下面这一段代码:

//---------------------------------------------------------

// 处理ActiveX Object时采用的页面切换代码

//---------------------------------------------------------

function writeXLS() {

//(略...)

excel.Quit();

excel = null;

// 下面代码用于解决IE call Excel的一个BUG, MSDN中提供的方法:

// setTimeout(CollectGarbage, 1);

// 由于不能清除(或同步)网页的受信任状态, 所以将导致SaveAs()等方法在

// 下次调用时无效.

location.reload();

}

delete 运算符在手册上的说明
引用从对象中删除一个属性,或从数组中删除一个元素。

delete expression

expression 参数是一个有效的 JScript 表达式,通常是一个属性名或数组元素。

说明

如果 expression 的结果是一个对象,且在 expression 中指定的属性存在,而该对象又不允许它被删除,则返回 false。

在所有其他情况下,返回 true。

最后之最后,关于GC的一个补充说明:在IE窗体被最小化时,IE将会主动调用一次CollectGarbage()函数。这使得IE窗口在最小化之后,内存占用会有明显改善

Javascript 相关文章推荐
学习JavaScript的最佳方法分享
Oct 21 Javascript
基于iframe实现类似于ajax的页面无刷新
May 31 Javascript
BootStrap实现带关闭按钮功能
Feb 15 Javascript
JS设置时间无效问题的解决办法
Feb 18 Javascript
jquery实现tab键进行选择后enter键触发click行为
Mar 29 jQuery
js 发布订阅模式的实例讲解
Sep 10 Javascript
解决vue-cli + webpack 新建项目出错的问题
Mar 20 Javascript
微信小程序中换行空格(多个空格)写法详解
Jul 10 Javascript
Angular resolve基础用法详解
Oct 03 Javascript
原生JS实现手动轮播图效果实例代码
Nov 22 Javascript
vue下的@change事件的实现
Oct 25 Javascript
分享8个JavaScript库可更好地处理本地存储
Oct 12 Javascript
script标签属性用type还是language
Jan 21 #Javascript
JS交换变量的方法
Jan 21 #Javascript
setinterval()与clearInterval()JS函数的调用方法
Jan 21 #Javascript
js实现DOM走马灯特效的方法
Jan 21 #Javascript
浅谈javascript 迭代方法
Jan 21 #Javascript
js实现用户注册协议倒计时的方法
Jan 21 #Javascript
浅谈javascript 归并方法
Jan 21 #Javascript
You might like
php中file_get_content 和curl以及fopen 效率分析
2014/09/19 PHP
php curl登陆qq后获取用户信息时证书错误
2015/02/03 PHP
PHP实现获取FLV文件的时间
2015/02/10 PHP
超详细的php用户注册页面填写信息完整实例(附源码)
2015/11/17 PHP
PHP正则获取页面所有图片地址
2016/03/23 PHP
[全兼容哦]--实用、简洁、炫酷的页面转入效果loing
2007/05/07 Javascript
document.getElementById方法在Firefox与IE中的区别
2010/05/18 Javascript
解决iframe的frameborder在chrome/ff/ie下的差异
2010/08/12 Javascript
javascript一个无懈可击的实例化XMLHttpRequest的方法
2010/10/13 Javascript
node.js使用nodemailer发送邮件实例
2014/03/10 Javascript
jQuery基础语法实例入门
2014/12/23 Javascript
javascript截图 jQuery插件imgAreaSelect使用详解
2016/05/04 Javascript
ashx文件获取$.ajax()方法发送的数据
2016/05/26 Javascript
jquery实用技巧之输入框提示语句
2016/07/28 Javascript
js简单时间比较的方法
2016/08/02 Javascript
使用OPENLAYERS3实现点选的方法
2020/09/24 Javascript
微信小程序自定义模态对话框实例详解
2017/08/16 Javascript
基于Vue 2.0 监听文本框内容变化及ref的使用说明介绍
2018/08/24 Javascript
Vue.js的动态组件模板的实现
2018/11/26 Javascript
ajax跨域访问遇到的问题及解决方案
2019/05/23 Javascript
Python里disconnect UDP套接字的方法
2015/04/23 Python
python搜索指定目录的方法
2015/04/29 Python
python和opencv实现抠图
2018/07/18 Python
tensorflow实现逻辑回归模型
2018/09/08 Python
python 自定义对象的打印方法
2019/01/12 Python
使用python实现数组、链表、队列、栈的方法
2019/12/20 Python
Python enumerate内置库用法解析
2020/02/24 Python
Python 实现将大图切片成小图,将小图组合成大图的例子
2020/03/14 Python
浅谈django 模型类使用save()方法的好处与注意事项
2020/03/28 Python
Python字符串及文本模式方法详解
2020/09/10 Python
CSS3制作hover下划线动画
2017/03/27 HTML / CSS
世界领先的艺术图书出版社:TASCHEN
2018/07/23 全球购物
工程师自我评价怎么写
2013/09/19 职场文书
母婴店促销方案
2014/03/05 职场文书
校庆接待方案
2014/03/18 职场文书
党员民主生活会个人整改措施材料
2014/09/16 职场文书