这可能取决于特定的垃圾收集器,因此答案取决于您使用的 JavaScript 引擎。
首先,我会注意到最好的应用程序代码会做两件事。它实现了功能和性能的技术目标,并且能够适应变化。附加代码应该足以证明增加的复杂性是合理的。
话虽如此,根据谷歌关于 V8 的注释,这是 Chrome 使用的 JavaScript 引擎,
V8 回收被称为垃圾收集的过程中不再需要的对象使用的内存。为了确保快速的对象分配、短的垃圾收集暂停和没有内存碎片,V8 采用了一个停止世界的、分代的、准确的垃圾收集器。这意味着 V8:
- 执行垃圾回收周期时停止程序执行。
- 在大多数垃圾回收周期中只处理对象堆的一部分。这最大限度地减少了停止应用程序的影响。
- 总是知道所有对象和指针在内存中的确切位置。这避免了将对象错误地识别为可能导致内存泄漏的指针。
在 V8 中,对象堆被分成两部分:创建对象的新空间,以及在垃圾回收周期中幸存的对象被提升到的旧空间。如果在垃圾回收周期中移动了一个对象,V8 会更新所有指向该对象的指针。
分代垃圾收集器倾向于在堆之间移动对象,其中所有活动对象都被移动到目标堆中。任何未移动到目的地的东西都被视为垃圾。目前尚不清楚 V8 垃圾收集器如何识别活动对象,但我们可以查看其他一些 GC 实现来寻找线索。
作为一个记录良好的 GC 实现的行为示例,Java 的 Concurrent Mark-Sweep 收集器:
- 停止应用程序。
- 构建可从应用程序代码访问的对象列表。
- 恢复应用程序。同时,CMS 收集器运行一个“标记”阶段,在此阶段它将传递可到达的对象标记为“非垃圾”。由于这与程序执行并行,它还跟踪应用程序所做的引用更改。
- 停止应用程序。
- 运行第二个(“remark”)阶段以标记新可到达的对象。
- 恢复应用程序。同时,它“清扫”所有标识为垃圾的对象并回收堆块。
它基本上是一个图遍历,从一组特定的节点开始。由于无法访问断开连接的对象,因此它们与其他断开连接的对象的连接不应该发挥作用。
在http://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf上有一份关于 Java 垃圾收集工作方式的不错的白皮书,虽然有些过时。垃圾收集并不是 Java 独有的,所以我怀疑 Java 虚拟机和其他运行时(如 JavaScript 引擎)采用的各种方法之间存在一些相似之处。
Raymond Chen 写了一篇博文指出,即将释放的步行记忆会对性能产生负面影响。上下文是在应用程序关闭时手动释放内存。由于块可能已被交换到磁盘,遍历引用的行为可能会导致这些块被交换。在这种情况下,程序正在遍历刚刚被标记为可用且保持不变的块。
因此,在操作系统可能已经换出一些块的情况下,“协助”垃圾收集器的行为,特别是在寿命较长的对象上,最终可能会减慢速度。
如果您没有生成足够的数据来担心换出,那么合理的垃圾收集器不会花费足够长的时间来注意到。
So chances are it's not worth the effort, and could be counterproductive. Although it probably makes sense to drop the references to the heap "dominators". These are the objects that, if collected, would allow the collection of many other objects. So drop the reference to the collection itself, but not to each item within the collection.