18

随着我越来越多地将 JavaScript 用作高级面向对象的语言,我发现自己像完成对象后的 C/C++ 程序员一样思考。我知道 GC 最终会运行并清理我的烂摊子,但是我能做些什么来真正帮助它吗?

例如,我有一个大/复杂的主要对象数组......每个主要对象可能有数组和其他辅助对象引用。如果我完成了一个主要对象并将其从数组中删除,那么 GC 可能最终会找出该对象本身指向的所有其他内容,循环内部引用等等。但是,从存储数组中删除主要对象以通过它并且 array.length=0 任何数组和 reference=null 任何对象基本上使 GC 工作更容易(例如,显式删除引用对 GC 来说意味着更少追踪)?如果你愿意的话,一种手动析构函数。这样做是否值得,还是我浪费时间/精力而获得很少/没有收益?

我想这更像是 GC 问题的一般理论(Java 等),但出于这个问题的目的,我主要对 JavaScript 感兴趣。

谢谢!

4

3 回答 3

5

很少。

这与从未不同。

通常,如果您以合理的方式进行开发,未使用的对象将适当地超出范围,垃圾收集器将按预期工作。除非您真正了解自己在做什么,否则帮助垃圾收集器完成其工作的努力通常不会按预期工作。垃圾收集是由各种 Javascript 引擎的创建者进行了重大优化的领域。一般来说,你不应该弄乱它,除非:

  • 您已经通过分析工具的硬数据向自己证明了存在真正的需求,并且
  • 您可以展示对实际需要更改的内容的真正理解,以帮助垃圾收集器。

这些都不是容易实现的。

所以也许最好的答案是,除非你已经足够先进来理解异常,否则你可能不应该担心这个。

于 2012-12-20T19:36:07.147 回答
5

这可能取决于特定的垃圾收集器,因此答案取决于您使用的 JavaScript 引擎。

首先,我会注意到最好的应用程序代码会做两件事。它实现了功能和性能的技术目标,并且能够适应变化。附加代码应该足以证明增加的复杂性是合理的。

话虽如此,根据谷歌关于 V8 的注释,这是 Chrome 使用的 JavaScript 引擎,

V8 回收被称为垃圾收集的过程中不再需要的对象使用的内存。为了确保快速的对象分配、短的垃圾收集暂停和没有内存碎片,V8 采用了一个停止世界的、分代的、准确的垃圾收集器。这意味着 V8:

  • 执行垃圾回收周期时停止程序执行。
  • 在大多数垃圾回收周期中只处理对象堆的一部分。这最大限度地减少了停止应用程序的影响。
  • 总是知道所有对象和指针在内存中的确切位置。这避免了将对象错误地识别为可能导致内存泄漏的指针。

在 V8 中,对象堆被分成两部分:创建对象的新空间,以及在垃圾回收周期中幸存的对象被提升到的旧空间。如果在垃圾回收周期中移动了一个对象,V8 会更新所有指向该对象的指针。

分代垃圾收集器倾向于在堆之间移动对象,其中所有活动对象都被移动到目标堆中。任何未移动到目的地的东西都被视为垃圾。目前尚不清楚 V8 垃圾收集器如何识别活动对象,但我们可以查看其他一些 GC 实现来寻找线索。

作为一个记录良好的 GC 实现的行为示例,Java 的 Concurrent Mark-Sweep 收集器:

  1. 停止应用程序。
  2. 构建可从应用程序代码访问的对象列表。
  3. 恢复应用程序。同时,CMS 收集器运行一个“标记”阶段,在此阶段它将传递可到达的对象标记为“非垃圾”。由于这与程序执行并行,它还跟踪应用程序所做的引用更改。
  4. 停止应用程序。
  5. 运行第二个(“remark”)阶段以标记新可到达的对象。
  6. 恢复应用程序。同时,它“清扫”所有标识为垃圾的对象并回收堆块。

它基本上是一个图遍历,从一组特定的节点开始。由于无法访问断开连接的对象,因此它们与其他断开连接的对象的连接不应该发挥作用。

在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.

于 2012-12-20T19:52:42.270 回答
3

非常聪明的人在这些垃圾收集模型上下了很大功夫。您所做的任何事情都会大大提高他们实施的性能的可能性相对较低。

如果垃圾收集正在成为您的主要成本,那么您最好专注于减少必须进行垃圾收集的对象数量(考虑对象池模式

于 2012-12-20T19:33:03.587 回答