作为ECMAScriptv5,每次控件输入代码时,引擎都会创建一个LexicalEnvironment(LE)和一个VariableEnvironment(VE),对于函数代码,这两个对象是完全相同的引用,是调用NewDeclarativeEnvironment( ECMAScript v5 10.4. 3 ),函数代码中声明的所有变量都保存在VariableEnvironment ( ECMAScript v5 10.5 )的环境记录组件中,这就是闭包的基本概念。
让我感到困惑的是垃圾收集如何使用这种闭包方法,假设我有如下代码:
function f1() {
var o = LargeObject.fromSize('10MB');
return function() {
// here never uses o
return 'Hello world';
}
}
var f2 = f1();
在 line 之后var f2 = f1()
,我们的对象图将是:
global -> f2 -> f2's VariableEnvironment -> f1's VariableEnvironment -> o
因此,据我所知,如果 javascript 引擎使用引用计数方法进行垃圾收集,则该对象o
至少有1个引用并且永远不会被 GC。显然这会导致内存浪费,因为o
永远不会使用但总是存储在内存中。
可能有人会说引擎知道f2的VariableEnvironment没有使用f1的VariableEnvironment,所以整个f1的VariableEnvironment都会被GCed,所以还有一段代码可能会导致更复杂的情况:
function f1() {
var o1 = LargeObject.fromSize('10MB');
var o2 = LargeObject.fromSize('10MB');
return function() {
alert(o1);
}
}
var f2 = f1();
在这种情况下,f2
使用o1
存储在f1 的 VariableEnvironment 中的对象,因此f2 的 VariableEnvironment必须保留对f1 的 VariableEnvironment的引用,这导致o2
也无法进行 GC,从而进一步浪费内存。
所以我会问,现代 javascript 引擎(JScript.dll / V8 / SpiderMonkey ...)如何处理这种情况,是否有标准的指定规则或它是否基于实现,以及 javascript 引擎处理此类对象图的确切步骤是什么执行垃圾收集。
谢谢。