如何确定垃圾回收器正在收集哪些对象?

16

我有很大的垃圾收集暂停时间。在尝试修复问题之前,我希望能够确定最主要的对象。我已经查看了Chrome上的堆快照,但(如果我错了,请纠正我)似乎找不到任何被收集的指示器,只有占用内存最多的内容。是否有一种经验方法来回答这个问题,或者我仅限于根据经验进行猜测?


2
你如何确定暂停是由垃圾回收引起的? - pencil
你读过这个吗?http://gent.ilcore.com/2011/08/finding-memory-leaks.html?m=1 - yunzen
1
有两种方式——它们与 Chrome 中内存时间轴上的内存下降重合,在我强制代码进行大量迭代以不断诱发暂停时,垃圾收集是我分析结果中最耗时的部分(远远超过其他情况)。 - shino
@yunzen 不,我没有,谢谢。我可能会错过一些东西,但我不确定它是否对我有帮助。我很自信我没有泄漏,因为我的内存使用量并没有随着时间的推移而增长。 - shino
请查看Google的Web跟踪框架http://google.github.io/tracing-framework/advanced-features.html#heap-tracing和http://jankfree.org/。 - RoryKoehein
4个回答

9
在Chrome中,要检查操作之前和之后的情况,需要进行两次堆快照。
现在点击第二个快照。
在底部栏中,您将看到一个选择框,其中包含“摘要”选项。将其更改为“比较”。
然后,在旁边的选择框中选择要与之比较的快照(它应该自动选择快照1)。
作为结果,您将获得所需数据的表格,例如“新建”和“已删除”的对象。

7
随着最新版的Chrome发布,有一个新的工具可以方便地完成这种任务: "Record Heap Allocations" profiling类型。正如Rafał Łużyński所解释的,常规的"Heap SnapShot"比较工具无法提供此类信息,因为每次拍摄堆快照时,都会执行GC运行,因此GC对象永远不会成为快照的一部分。但是,“Record Heap Allocations”工具会不断记录所有分配的内存(这就是为什么在记录时应用程序可能会变得非常缓慢)。如果您经常遇到GC运行,则此工具可以帮助您识别代码中分配大量内存的位置。与Heap SnapShot比较相结合,您将看到在两个快照之间分配的内存通常比比较中看到的要多得多。在极端情况下,比较可能根本没有差异,而分配工具将向您显示大量已分配的内存(显然,在此期间必须进行垃圾回收)。
不幸的是,该工具的当前版本无法向您显示分配发生的位置,但是它将向您显示已分配的内容以及分配时保留的方式。从数据(以及可能的构造函数)中,您将能够识别自己的对象以及它们被分配的位置。

这听起来很不错,但似乎并没有起作用。GC任务正在清除约2MB的数据,但当我使用记录堆分配工具时,它只显示了微小的数据量(KB)。 - mark pavlis

3

请查看https://developers.google.com/chrome-developer-tools/docs/heap-profiling,尤其是Containment View。

Containment View本质上是您应用程序对象结构的“鸟瞰图”。它允许您窥视函数闭包的内部,观察共同组成JavaScript对象的VM内部对象,并了解应用程序在非常低的级别上使用多少内存。

该视图提供了几个入口点:

DOMWindow对象-这些对象被认为是JavaScript代码的“全局”对象;GC根-GC收集器实际使用的GC根;Native对象-browser对象“推送”到JavaScript虚拟机中以允许自动化,例如DOM节点、CSS规则(有关更多详细信息,请参见下一节)。下面是Containment View的示例:

enter image description here


1
据我所知,可以被垃圾回收的对象不会出现在这个视图中,因为在快照被拍摄之前,会进行一次 GC 运行。由于 OP 想知道哪些对象被 GC 回收了,这并没有真正帮助到他,或者说有帮助吗? - Sebastian

3
如果你正在尝试在几个可能的罪犯之间做出选择,你可以修改对象定义,将它们附加到全局范围(作为文档下的列表或其他内容)。 然后这将阻止它们被回收。这可能会使程序更快(它们没有被回收)或更慢(因为它们会累积并每次被标记和清除检查)。因此,如果你看到性能变化,你可能已经找到了问题所在。
另一种选择是查看每种类型创建了多少对象(在构造函数中设置计数器)。如果它们被频繁回收,也就意味着它们同样频繁地被创建。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接