这是否已进行垃圾回收?

3

我相信类似的问题之前已经被问过了,但是大量类似的问题并没有回答我的问题,所以我必须自己提问。

假设你有以下代码:

(function() {
    "use strict";
    var somearray=[1, 2, 3];
    for(var i=0; i<somearray.length; i++) {
        //do something
        }
    function loop() {
        //do something repeatedly
        requestAnimationFrame(loop);
        }
    loop();
    })();

由于变量i定义在一个永久循环的相同作用域中,即使未使用,它是否继续存在,等待可能最终被使用的可能性?或者JavaScript(特别是Chrome的V8)的垃圾回收器足够聪明,能够确定它是否会被使用?
我知道可以在循环中的某个位置添加console.log(i),然后只要它被引用,i将继续存在,但在继续存在的作用域内,如果没有引用它,它还会继续存在吗?

“重复执行某些操作”的代码是否引用了“somearray”变量?如果没有,那么它(可能)会被垃圾回收。 - Pointy
你是指 i 变量还是数组?“在循环中添加 console.log(i) 并且 i 将继续存在” 暗示着是 i 变量,但询问数组似乎更有意义? - adeneo
我想知道如果一个变量没有被引用,它是否会被垃圾回收(“它会在继续存在的作用域中继续存在吗?”)- 因为作用域不会消失,我很好奇作用域定义的变量是否会被回收。这个问题解决了你评论中的“可能性”。编辑:同时,我像adeneo所说的那样指的是变量i,谢谢。 - user1948076
2
如果“loop”函数声明了自己的“i”或“somearray”变量,或者根本没有引用它们,那么可以安全地假设现代JavaScript运行时将能够收集该空间。但是并不保证一定能够收集。这是一种动态语言,垃圾回收不是可检测的活动(除非通过外部工具)。 - Pointy
1
for循环没有特殊的作用域,因此只要您在外部IIFE的作用域内,i变量就可用,并且在最早之前不能被收集,这应该包括具有较低作用域的循环函数。 - adeneo
显示剩余2条评论
1个回答

2
这并不是关于垃圾回收的问题,而是关于闭包是否被优化的问题。执行环境的闭包优化器可能会确定嵌套函数未引用(闭合)变量,然后将它们从闭包环境中省略掉。如果是这种情况,则它们有资格进行垃圾回收。如果闭包优化器没有运行,或者它确定 i 和 somearray 被引用,或者它无法确定 i 和 somearray 的生命周期,则它们将不会被回收,因为闭包环境需要它们。
一个函数有一个隐含的环境,其中包括封闭函数中的所有局部变量(以及所有封闭它的函数)。该环境将捕获由这些变量引用的任何对象。闭包优化器静态分析函数以确定是否可以修剪环境以省略未引用的变量。如果变量从环境中省略,则它们在函数调用结束时就有资格进行垃圾回收。
所有现代 JavaScript 引擎都有闭包优化器。
一些常见的可能会禁用或限制闭包优化器的东西包括处于调试模式、使用直接 eval()、使用 arguments 数组、使用已弃用的特性,如 caller 等。
正如您所看到的,这显然取决于“\\重复执行某些操作”做什么以及代码在什么上下文中执行。
一种确保无论“\\重复执行某些操作”做什么都不会被捕获的方法是确保它们不再在作用域内。一个立即执行的函数就可以做到这一点,所以将您的代码更改为:
(function() {
  "use strict";
  (function() {
    var somearray=[1, 2, 3];
    for(var i=0; i<somearray.length; i++) {
      //do something
    }
   })();
  function loop() {
    //do something repeatedly
    requestAnimationFrame(loop);
  }
  loop();
})();

将确保数组不会在内存中挂起。


1
一个命名的函数表达式应该作为增强功能可用:(function loop(){requestAnimationFrame(loop)}()); 但不确定这在现今的IE中是否可行。 - RobG
这在IE 9及更高版本中有效,因为它是ECMA规范的一部分。 - chuckj
并非所有的浏览器都遵循规范。一些IE版本在命名函数表达式方面存在问题。 - RobG
我同意,这就是为什么我通过版本号来限定我的答案。从IE 9开始,IE遵循ECMA规范。参考页面描述的是在IE 9-11下仍然支持但仅在兼容模式和怪异模式下的早期IE 9行为。 - chuckj
@RobG 不是相关话题,但这是一个更简洁的方法,谢谢你额外提供的知识宝藏。 - user1948076
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接