Java OutOfMemoryError,但在JFR中看到的活动对象很少?

Java OutOfMemoryError,但在JFR中看到的活动对象很少?,java,out-of-memory,performance-testing,Java,Out Of Memory,Performance Testing,我有一些代码在内存错误中抛出 我将JVM设置为在OOM上转储,并在Java Flight Recorder中打开转储 在JFR中检查活动对象时,我看到的对象很少(少于60个) 如何找出触发OOM时内存中最大且不可收集的对象?由于所收集数据的性质,无法以自动方式执行此操作(如内存分析器工具使用堆转储) 你只能看到少数几个物体,这是完全正确的。原因在于低开销采样的工作原理——在每一个新的TLAB分配上,JFR都会介入并从旧的TLAB中获取一些对象。因此,您不会记录所有对象,只会记录被分配对象的代表性

我有一些代码在内存错误中抛出

我将JVM设置为在OOM上转储,并在Java Flight Recorder中打开转储

在JFR中检查活动对象时,我看到的对象很少(少于60个)


如何找出触发OOM时内存中最大且不可收集的对象?

由于所收集数据的性质,无法以自动方式执行此操作(如内存分析器工具使用堆转储)

你只能看到少数几个物体,这是完全正确的。原因在于低开销采样的工作原理——在每一个新的TLAB分配上,JFR都会介入并从旧的TLAB中获取一些对象。因此,您不会记录所有对象,只会记录被分配对象的代表性样本。这应该足以为您提供堆中对象的比例。此外,所有报告的对象都在记录转储点处于活动状态

如果您认为获得的样本太少,无法得出正确的结论,那么可能是相对于TLAB大小,您的堆很小,您可能希望减小TLAB大小。这在生产环境中是不可取的,因为不正确的TLAB设置会降低应用程序性能

如果您在记录期间在分析配置中设置了“内存泄漏检测”到“对象类型+分配堆栈跟踪+GC根路径”,那么您可以跟踪活动对象在创建后在代码中的位置,并且可以通过这种方式重建具有代表性的支配者树

如果您关心大对象本身意味着大(并且不保留堆的大部分),您可以通过查看“TLAB分配”页面和“TLAB之外的总分配”列来查找比TLAB大的对象。只有在分析配置将“内存分析”设置为“对象分配和升级”时,才会收集此数据


通过分析配置,我指的是当您开始使用JFR录制时,您使用
settings
选项指定的文件。可以使用JMC应用程序的“飞行记录模板管理器”创建此文件。

对象是经过采样的,因此您无法确保在OOM之前看到最大的对象

也就是说,60个样本通常足以发现内存泄漏,至少在应用程序运行一段时间并且泄漏的大小不可忽略的情况下是如此

开始时发生的示例通常是在整个应用程序期间都有的单例和静态对象。最后发生的示例通常是要进行垃圾收集的短期对象。在JMC中,您可以单击顶部时间线的“中间”来查找内存泄漏候选项。然后,您可以查看堆栈跟踪和GC根目录的路径,并查看是否看到可疑的内容

您还可以使用命令行工具执行以下操作:

$ jfr print --events OldObjectSample --stack-depth 64 recording.jfr
它将按时间顺序列出样品。查看每个样本可能比查看聚合更容易。详细描述了命令行方法