JavaScript 专家 : Do block-scopes with `{}` and anonymous functions both help garbage-collection?

标签 javascript ecmascript-6 v8 anonymous-function spidermonkey

在《You don't know JS: scopes & closures》一书中,Kyle simpson 指出 block 作用域变量有助于垃圾回收,具体示例如下:

function process(data) {
// do something interesting
}

{
let someReallyBigData = {};
process(someReallyBigData);
}

var btn = document.getElementById("my_button");
btn.addEventListener("click", function click(evt) {
console.log("Clicked!");    
}, false);

现在上面的例子应该有助于垃圾收集,因为变量 someReallyBigData 会在 block 结束后立即从内存中删除,不像这个例子,它对垃圾收集没有帮助-收藏:

function process(data) {
// do something interesting
}

var someReallyBigData = {};

process(someReallyBigData);

var btn = document.getElementById("my_button");
btn.addEventListener("click", function click(evt) {
console.log("Clicked!");    
}, false);

现在我确信这个人关于他提供的例子(第一个)是正确的;但是,我想知道如果我们使用匿名 IIFE(立即调用的函数表达式)以及普通的 var 而不是 {} curly,是否一切都会一样大括号和 let 变量。让我把它变成一个例子:

function process(data) {
// do something interesting
}

(function(){
var someReallyBigData = {};
process(someReallyBigData);
}());

var btn = document.getElementById("my_button");
btn.addEventListener("click", function click(evt) {
console.log("Clicked!");    
}, false);

从表面上看,他们应该做同样的事情;因为就像 block 作用域的 someReallyBigData 变量在代码块执行后不能再被任何东西访问一样,匿名函数中的代码一旦执行就不能被任何东西访问,任何东西,从任何地方。

那么,它们真的对 Javascript 引擎的垃圾回收机制有同样的影响吗?我几乎可以肯定是这种情况,直到我用谷歌搜索“匿名函数垃圾收集”,几乎所有出现的 Material 都只说负面的事情,比如“匿名函数导致内存泄漏”等等。

如果有人能阐明这件事,我会很高兴。

请不要忘记我的问题是针对我提供的示例的,谢谢!

最佳答案

(这里是 V8 开发人员。)是的,有几种方法可以使对象无法访问,至少包括以下所有方法:

  • 将内容放入 let block 作用域中声明的变量
  • 将内容放入 IIFE
  • 使用完后清除变量(varlet):someReallyBigData = null;

最终结果在所有情况下都是相同的:不再可达的对象有资格进行垃圾回收。

基于此处讨论的其他注释:

  • 问题中引用的建议对顶级代码有意义。在一个合理大小的函数中,我不会担心它——该函数可能很快就会返回,因此没有任何区别,因此您无需为这些考虑而增加负担。

  • “一个对象现在可以被释放”和“一个对象现在被释放”之间有很大的区别。让某些东西超出范围不会导致它立即被释放,也不会导致垃圾收集器运行得更频繁。这只是意味着每当垃圾收集器下一次决定去寻找垃圾时,相关对象将符合条件。

  • 无论是否匿名,IIFE 都是 IIFE。示例:

    (function I_have_a_name() {
      var someReallyBigData = ...;
    })();
    // someReallyBigData can be collected now.
    I_have_a_name();  // ReferenceError: I_have_a_name is not defined
    
  • 创建闭包本身并不能使事物保持活力。但是,如果闭包在其外部范围内引用变量,那么(当然!)只要闭包存在,就无法收集这些变量。示例:

    var closure = (function() {
      var big_data_1 = ...;
      var big_data_2 = ...;
      return function() { return big_data_1.foo; }
    })();
    // big_data_2 can be collected at this point.
    closure();  // This needs big_data_1.
    // big_data_1 still cannot be collected, closure might need it again.
    closure = null;
    // big_data_1 can be collected now.
    
  • 优化编译器对这一切影响不大。它通常在每个函数的基础上运行,并且通常不会优化顶层(因为大多数逻辑往往在函数中)。 一个函数中,优化编译器非常了解对象的生命周期(这是优化编译器的一部分)。

关于JavaScript 专家 : Do block-scopes with `{}` and anonymous functions both help garbage-collection?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46221001/

相关文章:

javascript - JQuery查找并更新子元素的属性然后返回父元素

javascript - 错误 : 'list' is not defined no-undef 'route' is not defined no-undef

javascript - 为什么应用 JSON.stringify 会占用这么多内存?

javascript - 各种Javascript优化项目如何影响DOM性能?

c++ - V8编译器错误

javascript - fadeIn 不起作用 jquery

javascript - 如何在生产环境中处理 NVM?

javascript - 处理使用对象破坏和对象休息的组件的 Prop 类型的正确方法是什么......传播收集 Prop

javascript - url 的常量前缀

javascript - 将 bool 状态传递给多个 child