知道了这些不符合规范的代码解析bug以后,我们如果用它的话,就会发现内存方面其实是有问题的,来看一个例子:
var f = (function(){ if (true) { return function g(){}; } return function g(){}; })();
我们知道,这个匿名函数调用返回的函数(带有标识符g的函数),然后赋值给了外部的f。我们也知道,命名函数表达式会导致产生多余的函数对象,而该对象与返回的函数对象不是一回事。所以这个多余的g函数就死在了返回函数的闭包中了,因此内存问题就出现了。这是因为if语句内部的函数与g是在同一个作用域中被声明的。这种情况下 ,除非我们显式断开对g函数的引用,否则它一直占着内存不放。
var f = (function(){ var f, g; if (true) { f = function g(){}; } else { f = function g(){}; } // 设置g为null以后它就不会再占内存了 g = null; return f; })();
通过设置g为null,垃圾回收器就把g引用的那个隐式函数给回收掉了,为了验证我们的代码,我们来做一些测试,以确保我们的内存被回收了。
测试
测试很简单,就是命名函数表达式创建10000个函数,然后把它们保存在一个数组中。等一会儿以后再看这些函数到底占用了多少内存。然后,再断开这些引用并重复这一过程。下面是测试代码:
function createFn(){ return (function(){ var f; if (true) { f = function F(){ return 'standard'; }; } else if (false) { f = function F(){ return 'alternative'; }; } else { f = function F(){ return 'fallback'; }; } // var F = null; return f; })(); } var arr = [ ]; for (var i=0; i < 10000; i++) { arr[i] = createFn(); }
通过运行在Windows XP SP2中的任务管理器可以看到如下结果:
IE6: without `null`: 7.6K -> 20.3K with `null`: 7.6K -> 18K IE7: without `null`: 14K -> 29.7K with `null`: 14K -> 27K
如我们所料,显示断开引用可以释放内存,但是释放的内存不是很多,10000个函数对象才释放大约3M的内存,这对一些小型脚本不算什么,但对于大型程序,或者长时间运行在低内存的设备里的时候,这是非常有必要的。
关于在Safari 2.x中JS的解析也有一些bug,但介于版本比较低,所以我们在这里就不介绍了,大家如果想看的话,请仔细查看英文资料。
延伸阅读
此文章所在专题列表如下:
- 我们应该如何去了解JavaScript引擎的工作原理
- JavaScript探秘:编写可维护的代码的重要性
- JavaScript探秘:谨慎使用全局变量
- JavaScript探秘:var预解析与副作用
- JavaScript探秘:for循环(for Loops)
- JavaScript探秘:for-in循环(for-in Loops)
- JavaScript探秘:Prototypes强大过头了
- JavaScript探秘:eval()是“魔鬼”
- JavaScript探秘:用parseInt()进行数值转换
- JavaScript探秘:基本编码规范
- JavaScript探秘:函数声明与函数表达式
- JavaScript探秘:命名函数表达式
- JavaScript探秘:调试器中的函数名
- JavaScript探秘:JScript的Bug
- JavaScript探秘:JScript的内存管理
- JavaScript探秘:SpiderMonkey的怪癖
- JavaScript探秘:命名函数表达式替代方案
- JavaScript探秘:对象Object
- JavaScript探秘:原型链 Prototype chain
- JavaScript探秘:构造函数 Constructor
- JavaScript探秘:可执行的上下文堆栈
- 执行上下文其一:变量对象与活动对象
- 执行上下文其二:作用域链 Scope Chains
- 执行上下文其三:闭包 Closures
- 执行上下文其四:This指针
- JavaScript探秘:强大的原型和原型链
- JavaScript函数其一:函数声明
- JavaScript函数其二:函数表达式
- JavaScript函数其三:分组中的函数表达式
- JavaScript函数其四:函数构造器
- JavaScript变量对象其一:VO的声明
- JavaScript变量对象其二:VO在不同的执行上下文中
- JavaScript变量对象其三:执行上下文的两个阶段
- JavaScript变量对象其四:关于变量
- JavaScript变量对象其五:__parent__ 属性
- JavaScript作用域链其一:作用域链定义
- JavaScript作用域链其二:函数的生命周期
- JavaScript作用域链其三:作用域链特征
- JavaScript闭包其一:闭包概论
- JavaScript闭包其二:闭包的实现
- JavaScript闭包其三:闭包的用法
本文地址:http://www.nowamagic.net/librarys/veda/detail/1637,欢迎访问原出处。
大家都在看