【问题标题】:Memory Allocation in Javascript for duplicate object [closed]Javascript中重复对象的内存分配[关闭]
【发布时间】:2013-10-02 06:32:21
【问题描述】:

假设我从 ajax 调用中得到的 ajax 响应为 5mb。

function(ajaxresponse){

    var ajaxdata = ajaxresponse;

    then

    var ajaxdata2 = ajaxresponse; //as per the reply below this is a reference and hence new memory isn't allocated

    var ajaxdata3 = JSON.parse(JSON.stringify(ajaxresponse));

}

会使用 15mb、10mb 还是 5mb?

【问题讨论】:

  • 5 MB - 您在复制参考资料 - 而不是数据
  • 我相信您只是在创建指向原始 'ajaxresponse' 参数的指针。所以没有新的内存分配。您可以通过更改 ajaxdata2 中的某些内容来测试这一点 - 它也应该在 ajaxdata 和 ajaxresponse 中更改
  • ajaxdata2 只是对ajaxdata 中的值的引用,不会创建新值。
  • 哇,这是我不知道的事情!
  • 是的,对不起...这是我提出问题的初衷...添加了评论,因此回复仍然具有相关性。

标签: javascript performance memory


【解决方案1】:

这很简单。 JavaScript 总是按值传递/分配,但对象的值从不真正分配给变量。在 JS 中考虑对象和内存管理的方式是这样的:

所有对象(无论是函数、对象字面量、数组、原型...)都驻留在内存中的某个位置。内存中的这些空间可以被变量引用,也可以不被引用。但他们保持原样放置。您可以为任意数量的变量分配此对象的地址,但您不能复制对象本身,也不能直接复制。
查看this answer,其中包含许多图表以及有关 JS 工作原理的更多详细信息,包括指向更多信息的链接...

试试吧:

var a = {foo: 'bar'},
b;
b = a;
console.log(b.foo);//bar
b.foo += ' appended through b reference';
console.log(a.foo);//bar appended through b reference

ab 引用相同的 对象,不需要额外的内存...除了存储b 变量所需的微小内存位。
在此示例中,实际 值是ab,类似于0XB16B00B6。或者在 C 语言中,它们实际上表现为一个取消引用的指针。


在某些情况下,人们确实想要复制对象。由于 JS 的设计,现在这很难实现。如果对象只包含数据,那么最简单的方法是:

var copiedObj = JSON.parse(JSON.stringify(someObject));

但是,如果您要处理的对象也带有自己的方法,那么您将进入一个全新的麻烦世界,您将不得不执行以下操作:

//after doing:var copiedObj = JSON.parse(JSON.stringify(someObject));
function copyFunctions(srcObj, targetObj)
{
    var prop;
    for (prop in srcObj)
    {
        if (srcObj[prop] instanceof Object)
        {
            if (srcObj[prop] instanceof Function)
            {
                targetObj[prop] = srcObj[prop];//this is a REFERENCE, still
                //OR, to ensure correct this binding!
                targetObj[prop] = (function(rebind, actualFunc)
                {
                    return function()
                    {
                        actualFunc.bind(this);
                        var returnVal = actualFunc.apply(this, [].slice.call(arguments));
                        actualFunc.bind(rebind);
                    };
                }(srcObj, srcObj[prop]));
            }
            else
            {
                if (srcObj.hasOwnProperty(prop))
                {//avoid copying prototypal methods
                    targetObj[prop] = copyFunctions(srcObj[prop], targetObj[prop] || {});
                }
            }
        }
    }
    return targetObj;
}

请注意,这段代码只是在我脑海中浮现,并没有经过任何测试。它不检查递归,所以使用起来不安全......但我希望你能明白它的要点。

现在,您问题中的代码如何改变内存使用情况?很简单:JSON.stringify 返回一个字符串常量。这个字符串不再绑定到原来的对象,所以JS会分配新的内存来容纳这个字符串的内存。然后,这个字符串被传递给JSON.parse。同样,将创建一个新对象,需要为此对象(不引用原始对象)分配内存。
分配给ajaxdata3 后,GC (GarbageCollector) 启动。它会找到对单个对象的 2 个引用,因此该对象不能被 GC'ed。它还将注册第二个对象,该对象被变量ajaxdata3 引用,因此该对象也将保留在内存中。
也找到了JSON.stringify 的返回值,只是这一次,GC 发现这个字符串常量没有在任何地方被引用,所以它标记了内存的那个部分。下次 GC 启动时,它将检查所有 标记 位内存并释放它们(释放它们以供使用)。

【讨论】:

  • 谢谢你让我大开眼界!
  • 我更改了代码,使其不再是参考。内存分配会受到怎样的影响?
  • @ZendNoob:你是如何更改代码的? JSON.stringify?因为如果它是一个对象,它就永远是一个引用......
  • 是的,我改了代码,现在内存会受到怎样的影响?
  • 所以 ajaxdata3 仍然是参考而不是新内容?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
  • 1970-01-01
  • 2014-02-24
相关资源
最近更新 更多