由于我更多地使用JavaScript作为高级面向对象语言,我发现自己像C / C ++程序员一样思考我在完成对象时的情况。我知道GC最终会运行并清理我的烂摊子,但我能做些什么才能真正帮助它?
例如,我有一个大型/复杂主要对象的数组......每个主要对象可能都有数组和其他辅助对象引用。如果我已完成主要对象并将其从数组中删除,那么GC可能最终会找出对象所指向的所有其他内容,循环内部引用和所有内容。但是当从存储阵列中删除主要对象以通过它并且array.length = 0时,任何数组和reference = null任何对象基本上使GC工作变得更容易(例如显式删除引用意味着GC更少跟踪)?如果你愿意,那种手动析构函数。这样做是值得的还是我浪费时间/精力来获得很少/没有收获?
我认为这更像是GC问题的一般理论(Java等),但我对这个问题的目的主要是对JavaScript感兴趣。
谢谢!
答案 0 :(得分:5)
很少。
与永远不同。
通常,如果以合理的方式开发,未使用的对象将被适当地超出范围,并且垃圾收集器将按预期工作。除非你真正理解你在做什么,否则帮助垃圾收集器完成工作的努力往往不能按预期工作。垃圾收集是一个由各种Javascript引擎的创建者进行了重大优化的区域。一般来说,除非:
,否则不应该乱用它这些都不容易实现。
所以也许最好的答案是,除非你已经足够先进以理解异常,否则你可能不应该担心这一点。
答案 1 :(得分:4)
这可能取决于特定的垃圾收集器,因此答案取决于您使用的JavaScript引擎。
首先,我会注意到最好的应用程序代码可以完成两件事。它实现了功能和性能的技术目标,并且具有变革的弹性。附加代码应足以达到增加复杂性的目的。
据说,根据Google's notes on V8,这是Chrome使用的JavaScript引擎,
V8回收了a中不再需要的对象使用的内存 过程称为垃圾收集。为了确保快速的对象分配, 短暂的垃圾收集暂停,没有内存碎片V8 采用世界一流的,世代的,准确的垃圾收集器。 这意味着V8:
- 在执行垃圾回收循环时停止程序执行。
- 在大多数垃圾收集周期中仅处理对象堆的一部分。这可以最大限度地减少停止应用程序的影响。
- 始终确切知道所有对象和指针在内存中的位置。这可以避免错误地将对象识别为可能导致的指针 内存泄漏。
在V8中,对象堆被分为两部分:new space where 创建对象,以及对象存活的旧空间 垃圾收集周期得到提升。如果一个对象被移动到 垃圾收集周期,V8更新指向对象的所有指针。
分代垃圾收集器倾向于在堆之间移动对象,其中所有活动对象都移动到目标堆中。任何未移动到目的地的东西都被认为是垃圾。目前尚不清楚V8垃圾收集器如何识别活动对象,但我们可以查看其他一些GC实现的线索。
作为一个记录良好的GC实现行为的一个例子,Java的Concurrent Mark-Sweep收集器:
它基本上是一个图遍历,从一组特定节点开始。由于无法访问断开连接的对象,因此它们与其他断开连接的对象的连接不应起作用。
关于Java垃圾收集在http://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf的工作方式,有一篇很好的,有点过时的白皮书。垃圾收集并不是Java独有的,因此我怀疑Java虚拟机和其他运行时(如JavaScript引擎)采用的各种方法之间存在某些相似之处。
Raymond Chen写了一篇blog post,指出你即将释放的行走记忆会对性能产生负面影响。上下文是关于在应用程序关闭时手动释放内存。由于块可以交换到磁盘,遍历引用的行为可以导致这些块被交换。在这种情况下,程序正在遍历那些刚被标记为可用且未触及的块。因此,在操作系统可能已经换出一些块的情况下,“协助”垃圾收集器的行为,特别是对于寿命较长的对象,可能最终会减慢速度。
如果您没有生成足够的数据来关注交换,那么合理的垃圾收集器不会花费足够长的时间来注意。
所以很有可能它不值得努力,并且可能适得其反。尽管删除对堆“dominators”的引用可能是有意义的。这些对象如果被收集,将允许收集许多其他对象。因此,删除对集合本身的引用,但不删除集合中的每个项目。
答案 2 :(得分:3)
非常聪明的人在垃圾收集模型上非常努力。你所做的任何事情的可能性都大大提高了他们实施的表现相对较低的表现。
如果垃圾收集成为您的主要成本,您最好集中精力减少必须进行垃圾收集的对象数量(考虑Object Pool Pattern)