x = undefined;
这意味着没有任何东西保留了对所使用的对象 x
的引用。因此,即使 x
仍然存在,至少它所引用的对象已经准备好被回收了。这是无害的。但是,现代引擎会为您优化这些内容,除非您面临特定的性能问题并将其追踪到某些在函数返回后不再引用但似乎没有被清理的大型对象分配代码,否则不必担心它。
不幸的是,正如您在下面指出的那样,这种方法也有其限制,比如在这个问题中提到的限制。但不要绝望,接下来在配置文件快照下面可以看到您可以做些什么……
让我们使用Chrome的堆快照功能,在V8中查看这段代码:
function UsedFlagClass_NoFunction() {}
function UnusedFlagClass_NoFunction() {}
function build_NoFunction() {
var notused = new UnusedFlagClass_NoFunction();
var used = new UsedFlagClass_NoFunction();
return function() { return used; };
}
function UsedFlagClass_FuncDecl() {}
function UnusedFlagClass_FuncDecl() {}
function build_FuncDecl() {
var notused = new UnusedFlagClass_FuncDecl();
var used = new UsedFlagClass_FuncDecl();
function unreachable() { notused; }
return function() { return used; };
}
function UsedFlagClass_FuncExpr() {}
function UnusedFlagClass_FuncExpr() {}
function build_FuncExpr() {
var notused = new UnusedFlagClass_FuncExpr();
var used = new UsedFlagClass_FuncExpr();
var unreachable = function() { notused; };
return function() { return used; };
}
window.noFunction = build_NoFunction();
window.funcDecl = build_FuncDecl();
window.funcExpr = build_FuncExpr();
下面是扩展的堆快照:
在处理build_NoFunction
函数时,V8成功地确定了从notused
引用的对象无法访问并将其清除,但是在其他两种情况下却没有这样做,尽管unreachable
无法访问,因此notused
也无法通过它访问。
那么我们该怎么避免这种不必要的内存消耗呢?
对于可以通过静态分析来处理的任何内容,我们可以使用JavaScript到JavaScript编译器(如Google的Closure Compiler)。即使在“简单”模式下,使用Closure Compiler “编译”上述代码的美化结果如下:
function UsedFlagClass_NoFunction() {}
function UnusedFlagClass_NoFunction() {}
function build_NoFunction() {
new UnusedFlagClass_NoFunction;
var a = new UsedFlagClass_NoFunction;
return function () {
return a
}
}
function UsedFlagClass_FuncDecl() {}
function UnusedFlagClass_FuncDecl() {}
function build_FuncDecl() {
new UnusedFlagClass_FuncDecl;
var a = new UsedFlagClass_FuncDecl;
return function () {
return a
}
}
function UsedFlagClass_FuncExpr() {}
function UnusedFlagClass_FuncExpr() {}
function build_FuncExpr() {
new UnusedFlagClass_FuncExpr;
var a = new UsedFlagClass_FuncExpr;
return function () {
return a
}
}
window.noFunction = build_NoFunction();
window.funcDecl = build_FuncDecl();
window.funcExpr = build_FuncExpr();
从上面可以看到,静态分析告诉编译器该代码中的unreachable
是无用代码,因此完全将其删除。
但是,在函数执行期间,您可能会使用unreachable
,只是在函数完成后不再需要它。它不是无用代码,但是当函数结束时,您不需要它。在这种情况下,您必须采取以下措施:
unused = undefined;
最后,在不再需要该函数时,您可以将其释放:
unused = unreachable = undefined;
unreachable = undefined;
截至目前(本文撰写时),它不能使V8发现unused
可以被清除掉。:(
x
是否已经被保留,因此删除它的实现完全符合规范(你需要使用内存分析器或类似工具才能确定,这超出了规范的范围)。 - T.J. Crowder