8

通过 JMX 在 JVisualVM 中查看我的远程应用程序时,我看到空闲时内存使用情况呈锯齿状:

在此处输入图像描述

进行堆转储并使用 JVisualVM 对其进行分析,我看到一大块内存位于几个int[]没有引用的大数组中,通过比较堆转储,我可以看到似乎是这些正在占用内存并被回收定期进行 GC。

我很想追踪这些,因为它激起了我的兴趣,即我自己的代码从不故意分配任何int[]数组。

我确实使用了很多像 netty 这样的库,所以罪魁祸首可能在其他地方。我确实有其他具有相同框架组合的服务器,但在那里看不到这个锯齿。

我怎样才能发现谁在分配它们?

4

2 回答 2

3

进行堆转储并找出持有它们的对象。一旦你知道哪些对象持有数组,你应该很容易弄清楚是什么在分配它们。

它没有回答你的问题,但我的问题是:

你为什么在乎?

您已经告诉 jvm 垃圾收集器 (GC) 它最多可以使用 1GB 内存。Java 使用少于 250M。

GC 试图对它何时进行垃圾收集以及它在垃圾收集时的工作强度进行智能处理。在您的图表中,没有对内存的需求。jvm 并不接近您设置的 1GB 限制。我认为 GC 完全没有理由非常努力。不知道你为什么会关心。

垃圾收集器懒惰是件好事。GC 工作越少,您的应用程序可用的资源就越多。

您是否尝试过通过 JVisualVM 的“Perform GC”按钮触发 GC?该按钮应触发“停止世界”垃圾收集操作。当图表位于其中一个锯齿上升的中间时尝试一下 - 我预测使用量将下降到锯齿的底部或以下。如果是这样,那就证明内存锯齿只是垃圾堆积,而 GC 正在做正确的事情。

这是我使用的 java swing 应用程序的内存使用截图: 在此处输入图像描述

注意锯齿图案。

你说你担心 int[]。当我启动内存分析器并对其进行分析时,我可以看到 int[] 的分配

在此处输入图像描述

基本上所有分配都来自 ObjectOutputStream$HandleTable.growEntries 方法。看起来分配的线程被启动以处理网络消息。
我怀疑它是由 jmx 本身引起的。可能通过 rmi(你使用 rmi 吗?)。或调试器(您是否连接了调试器?)。

于 2013-06-17T20:57:09.903 回答
1

int[]我只是想补充一下这个问题,锯齿模式非常正常,与您的阵列无关。之所以会发生这种情况,是因为 Eden-gen 中发生了新的分配,并且只有在填满后才会触发临时收集,而留下 old-gen。因此,只要您的程序进行任何分配,Eden gen 就会填满然后反复清空。尤其是,当您在单位时间内有固定数量的分配时,您会看到非常规则的锯齿模式。

网上有很多文章详细介绍了 Hotspot 的 GC 是如何工作的,所以我没有必要在这里展开。如果您完全不知道临时收集是如何工作的,您可能需要查看Wikipedia 关于该主题的文章(请参阅“Generational GC”部分;“generational”和“ephemeral”在这种情况下是同义词)。

然而,至于int[]阵列,它们有点神秘。我也看到了这些,这里还有一个关于它们的问题,没有任何真正的答案。没有引用的对象出现在堆转储中实际上是不正常的,因为堆转储通常只包含活动对象(因为 Hotspot 总是在实际转储堆之前执行停止世界的收集)。我个人的猜测是,它们是作为某种内部 JVM 数据结构的一部分分配的(因此只有来自 Hotspot 的 C++ 部分的引用,而不是来自 Java 堆的引用),但这实际上只是一个纯粹的猜测。

于 2013-12-18T06:32:15.053 回答