有没有一种(简单)的方法来确定GC正在“删除”的对象?

4
我有一个Java程序,它创建了大约12个长度为1.6亿的数组。这些数组包含原始数据类型(char、short和float)。在我的算法中,我通过jprofiler发现GC在我的系统上运行得相当频繁(Google Cloud上的Windows VM机器,16个CPU核心,64GB RAM),但我无法弄清楚为什么GC会如此经常地运行并占用总计算CPU功率的80%。
因此,我想:如果我能找出(通过jvm命令/日志或最好是通过像jprofiler这样的分析器)精确哪些对象被“垃圾回收”,我就有可能了解到发生了什么,要么修复简单问题,要么根据更好的理解重新设计。 (据我所知,我已尽量减少对象创建;虽然我确实使用了很多jdk8并行流特性,但我不知道是否会导致GC问题。)是否有一种方法可以确定GC在任何特定时间正在尝试清理哪些对象(或哪些对象类型),以便我更好地了解GC为什么会如此频繁且如此努力地运行?

1
只是为了正确理解:您没有意识到可能存在问题,即没有性能问题,直到分析工具告诉您GC花费了80%的CPU时间?也许,只是因为您的应用程序不需要太多的CPU时间?除此之外,您过于关注无关紧要的细节。您应该注意的第一件事是,“JVM分配了多少堆内存?”和“JVM实际上使用了多少堆空间?” - Holger
我注意到CPU的使用率没有达到100%(这是我预期的),经过分析发现JVM垃圾回收运行了不少。至于你其他两个问题的答案,我已将-Xmx设置为33G,但我注意到“已使用大小”(根据jprofiler)的数量在11G到15G之间变化,而提交的大小则在16G到25G之间变化。我猜想,目前没有明确(或者至少“简单”)的方法来确定GC正在“收集”的哪些对象(或对象类型),以便我可以追踪(潜在的)问题? - Jonathan Sylvester
1
问题在于,与口语中所说的“垃圾收集器”不同,JVM 不会收集垃圾,而是遍历可达的对象,因此仍然存在。将这些对象移动到新的内存区域后,整个源内存块可以被视为自由的,而不知道它以前包含了什么样的旧对象。这意味着 a) 我们不能识别这些死亡对象而需要额外的努力 b) 我们不希望或需要识别它们,因为这些旧对象不会对 JVM 造成任何工作负担。仍然存活的对象很重要,例如当堆几乎满时。 - Holger
1
但是由于垃圾回收确实使用了CPU,不使用100%的CPU表明垃圾回收在这里根本不是性能因素。拥有一个甚至没有完全填满的堆支持这个假设。显然,您的应用程序的性能受到I/O操作的影响(或者它没有足够的工作/线程来利用所有的CPU,或者受到锁定的影响)。 - Holger
@Holger 非常好的观点...我会进行调查的... - Jonathan Sylvester
1个回答

0
在JProfiler中,您可以使用分配记录来实现此目的。
要在“已记录对象”视图中显示垃圾收集的对象,请将工具栏中的存活性选择器更改为“垃圾收集的对象”或“活动和垃圾收集的对象”。分配调用树和分配热点视图的选项对话框具有等效的下拉菜单。

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