如果两个JavaScript对象数组共享元素,那么当不再引用一个数组时,是否所有非共享内存都被垃圾收集?

时间:2016-11-30 22:55:03

标签: javascript arrays object memory-leaks garbage-collection

当两个数组有一个指向(引用)同一个对象的元素,并且你通过一个数组更改对象时,它会在另一个数组中发生变化,正如我在下面的第一个片段中证明的那样。

我的问题是,如果在其他代码中引用了数组a1,例如事件处理程序,并且a2未在其他任何地方引用并超出范围,那么请对所有“主要”浏览器进行垃圾收集。 a2数组本身,包括指向对象的指针,以及下面代码段中第二次推送中创建的对象的内存。如果是这样,那么因为a2不再有指向a1中对象的指针,那么如果a1最终超出范围,那么所有它的相关内存,包括它所指向的所有对象,都将由GC回收,假设没有其他指针除了那些与a1和a2相关的那些,引用那些对象?

我知道这个简单的例子似乎是学术性的,但是我正在编写一个算法(参见第2个片段),从数组中相同数据的扁平版本制作嵌套对象,并且这样做我使用临时数组其中元素指向原始数组中的每个对象。我计划无限期地调用它,我想确保我不会泄漏记忆。数组中的元素将多于片段中的元素。

我也知道还有其他SO问题与这个问题有很大的相似之处,答案很有帮助,但我认为没有人能够明确回答每个部分。

var a1 = [{first: 1, second: 2}, {first: 4, second: 2}, {first: 3, second: 4}];
var a2 = [a1[2]];

a2.push(a1[1]);
a2.push({first: 5, second: 8});

console.log('a1 = ' + JSON.stringify(a1, null));
console.log('a2 = ' + JSON.stringify(a2, null));

a2[0].first = 7;
a2[1].second = 9;

console.log('a1 = ' + JSON.stringify(a1, null));
console.log('a2 = ' + JSON.stringify(a2, null));

var events = [
  {
    "id": 7,
    "parentId": 4,
    "name": "Sub7",
    "expected": 400,
    "actual": 100
  },
  {
    "id": 2,
    "parentId": 1,
    "name": "Sub2",
    "expected": 200,
    "actual": 100
  },
  {
    "id": 4,
    "parentId": 1,
    "name": "Sub4",
    "expected": null,
    "actual": 100
  },
  {
    "id": 8,
    "parentId": 1,
    "name": "Sub8",
    "expected": 250,
    "actual": 100
  },
  {
    "id": 1,
    "parentId": null,
    "name": "Main",
    "expected": null,
    "actual": 100
  },
  {
    "id": 6,
    "parentId": 4,
    "name": "Sub6",
    "expected": 300,
    "actual": 100
  }
];

var temp = [];
var parent;

for (var i = 0; i < events.length; i++) {
  
  if (temp[events[i].id]) {
    Object.assign(temp[events[i].id], events[i]);
  } else {
    temp[events[i].id] = events[i];
    temp[events[i].id].children = [];
  }

  var parentId = events[i].parentId;
  if (!parentId) {
    parent = temp[events[i].id];  
  } else {
    if (!temp[parentId]) {
      temp[parentId] = {
        id: parentId,
        parentId: undefined,
        name: undefined,
        expected: undefined,
        actual: undefined,
        children: [temp[events[i].id]]
      }
    } else {
      temp[parentId].children.push(temp[events[i].id]);
    }
  }
  
  delete temp[events[i].id].parentId;
}

temp = undefined;

document.write('<code><pre>' + JSON.stringify(parent, null, 2) + '</pre></code>');

2 个答案:

答案 0 :(得分:1)

简短版本如下:如果没有代码可以访问它,它将被垃圾收集。

您可以想象一个从根节点开始的图形(想象window),每个后续节点都是可以从该节点访问的数据。在你的情况下,你得到这样的东西:

root --> event handler --> array1 ---
                                    V
                                    object
                                    ^
                           array2 ---

您可以看到有一条路径通过array1返回到根目录。 array2不存在此类路径。因此,array2将被清除,并且任何也没有返回根目录的值也将被清除。

object 确实通过array1返回到根目录的路径。因此,系统会收集array2 s 参考,但组成object的实际数据不会。

答案 1 :(得分:1)

实际上非常简单。只要通过代码无法访问项目(某些内容超出范围),就会将其标记为删除。是否在那一刻收集垃圾是实现的细节,但它将不再在代码中可用。

因此,当array2超出范围时,它的数据将消失,但如果array1中的一个元素在array1中使用,则该单个数据将不会消失。

<强> Here's more on that.