本文详解IE浏览器特有的CollectGarbage函数,通过四个示例解析对象失效与释放的区别。针对ActiveX对象(如Excel操作),阐述先置null再调用GC的标准流程,并指出IE缓存权限凭证导致的局限,推荐页面重载作为更可靠的解决方案。
JavaScript CollectGarbage函数案例详解
首先观察一个涉及内存释放的具体实例:
<SCRIPT LANGUAGE="JavaScript">
<!--
strTest = "1";
for ( var i = 0; i < 25; i ++ )
{
strTest += strTest;
}
alert(strTest);
delete strTest;
CollectGarbage();
//-->
</SCRIPT>
CollectGarbage是Internet Explorer浏览器特有的一个属性,专门用于执行内存释放操作。其标准使用流程为:先将目标变量或引用对象设置为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。其实并非如此,这是操作系统、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环境中非常有效。一些潜在的ActiveX Object包括XML、VML、OWC(Office Web Component)、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。
最后补充说明:在IE窗口被最小化时,IE将会主动调用一次CollectGarbage()函数。这使得IE窗口在最小化之后,内存占用会有明显改善。
到此这篇关于JavaScript CollectGarbage函数案例详解的文章就介绍到这了,更多相关js CollectGarbage函数内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!