javascript - 为什么函数创建并返回的对象在函数执行结束后还继续存在?

标签 javascript memory-management

我读到每个函数都有自己的堆栈,这意味着当函数结束时,它的变量不再保存在内存中。我还读到对象通过引用返回。

考虑这个例子:

function getObject() {
 var obj = {name: "someName"};
 return obj;
} //At the end the locals should disappear


var newObj = getObject();// Get reference to something that is no longer kept in the stack,
console.log(newObj);//

因此,如果函数的返回值是对不再存在(在堆栈中)的对象的引用,我们如何仍然获得正确的值?在 C(语言)中返回指向局部变量的指针是疯狂的。

最佳答案

首先,快速免责声明:理论与现代 JavaScript 引擎实际执行的优化过程之间存在差异。

让我们从理论开始:

对象 不在堆栈上,只是包含对对象的引用的变量。该对象单独存在,并在堆中创建。所以在你的例子中,就在函数返回之前,我们在内存中有这个:

                    +−−−−−−−−−−−−−−−−−−+
                    |     (object)     |
                    +−−−−−−−−−−−−−−−−−−+
[obj:Ref11254]−−−−−>| name: "someName" |
                    +−−−−−−−−−−−−−−−−−−+

obj, the variable, contains a reference to the object (Ref11254, though of course that's just a conceptual number, we never actually see these). When your function returns, the content of obj (Ref11254) is returned, and obj (the variable) disappears along with the rest of the stack. But the object, which exists separately, continues to exist as long as something has a reference to it — in your case, the newObj variable.

In practice:

As an optimization, modern JavaScript engines frequently allocate objects on the stack (subject to engine-specific size constraints). Then, if the object is going to continue to live after the function terminates and the stack is cleaned up, they copy it into the heap. But if the object isn't going to survive (that is, no reference to it has been kept or is being returned), they can let it get cleaned up along with the stack. (Why? Because stack allocations and cleanup are really fast, and a lot of objects are only used locally in functions.)


It's worth noting that the same question arises for variables if the function creates a function:

function getFunction() {
    var x = 0;
    return function() {
        return x++;
    };
}
var f = getFunction();
console.log(f()); // 0
console.log(f()); // 1
console.log(f()); // 2

现在不仅 getFunction 返回的函数(它是一个对象)存活了下来,而且 x 也存活了下来!即使变量“在堆栈上”,并且当 getFunction 返回时堆栈也会被回收。这怎么可能?!

答案是,从概念上讲,局部变量在堆栈上。将它们放在堆栈上是一种优化(一种常见的优化)。从概念上讲,局部变量(连同其他一些东西)存储在一个名为 LexicalEnvironment 对象 的对象中,该对象是为调用 getFunction 而创建的。从概念上讲,getFunction 返回的函数具有对该 LexicalEnvironment 对象的引用,因此它(及其包含的变量)即使在 getFunction 返回后仍继续存在。 (getFunction 返回的函数称为 闭包,因为它关闭创建它的环境。)

果然,在实践中,现代 JavaScript 引擎并没有真正做到这一点。他们在堆栈上创建变量,可以快速轻松地清理它们。但是如果一个变量需要继续存在(就像我们上面的例子中的 x 需要),引擎会将它(以及它需要保留的任何其他变量)放入容器中堆并让闭包引用该容器。

有关闭包的更多信息,请参阅 this question's answerson my anemic little blog (使用稍微过时的术语)

关于javascript - 为什么函数创建并返回的对象在函数执行结束后还继续存在?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48600442/

相关文章:

javascript - 我可以让 Visual Studio 2008 中的 C# 代码编辑器显示行分隔方法吗?

java - 如果达到内存大小限制,如何从 map 中删除元素?

javascript - 为什么 'document' is not defined 在 webpack 构建时出错?

javascript - 在javascript中从另一个html元素获取元素内容

c++ - 使用两个模板参数创建最简单的分配器

ruby-on-rails - 在 heroku 上设置 WEB_CONCURRENCY 的公式是什么?

c - 记录动态内存分配使用情况

ios - iOS 是否接受任何内存泄漏?

javascript - 循环加载 jquery 并等待完成

javascript - 比较两个 html block 是否具有相同的内容