当通过JMX在JVisualVM中查看我的远程应用程序时,我看到了空闲时内存使用情况:
采用堆转储并使用JVisualVM进行分析,我看到一大块内存存在于几个没有引用的大int[]
数组中,通过比较堆转储,我可以看到它似乎是这些正在记忆并由GC定期收回。
我很想跟踪这些,因为它引起了我的兴趣,我自己的代码永远不会故意分配任何int[]
数组。
我确实使用了很多像netty这样的库,所以罪魁祸首可能在其他地方。我确实有其他服务器具有相同的框架组合,但在那里看不到这个锯齿。
我怎样才能发现谁在分配它们?
答案 0 :(得分:3)
获取一个堆转储并找出哪些对象持有它们。一旦你知道什么对象持有数组,你应该有一个简单的时间想法,找出分配它们的内容。
它没有回答你的问题,但我的问题是:
为什么要关心?
你告诉jvm垃圾收集器(GC)它可以使用高达1GB的内存。 Java的使用量不到250M。
GC试图了解垃圾收集的时间以及它在垃圾收集中的工作方式。在图表中,不需要内存。 jvm并不接近你设置的1GB限制。我认为GC没有理由应该非常努力。不知道为什么你会关心。
垃圾收集器懒惰是件好事。 GC运行的越少,您的应用程序可用的资源就越多。
您是否尝试通过JVisualVM“执行GC”按钮触发GC?该按钮应触发“停止世界”垃圾收集操作。当图表处于其中一个锯齿斜坡的中间时尝试它 - 我预测使用将下降到锯齿的底部或以下。如果确实如此,那证明记忆锯齿只是垃圾堆积而GC正在做正确的事情。
以下是我使用的java swing应用程序的内存使用情况的屏幕截图:
注意锯齿模式。
你说你担心int []。当我启动内存分析器并让它描述一切时,我可以看到int []
的分配
基本上所有分配都来自ObjectOutputStream $ HandleTable.growEntries方法。它看起来像分配的线程被旋转以处理网络消息 我怀疑它是由jmx本身引起的。可能是rmi(你用rmi吗?)。或调试器(您是否连接了调试器?)。
答案 1 :(得分:1)
我只是认为我会在这个问题中添加锯齿模式非常正常,并且与int[]
数组没有任何关系。之所以发生这种情况,是因为新的分配发生在Eden-gen中,而短暂的集合只有在填满之后才会触发,留下旧的。因此,只要您的程序完成任何分配,Eden gen就会填满然后反复清空。特别是,当你每单位时间有一定数量的分配时,你会看到一个非常规则的锯齿模式。
网上有大量文章详细介绍了Hotspot GC的工作原理,因此我无需在此处进行扩展。如果您根本不知道短暂收集的工作原理,您可能需要查看Wikipedia's article on the subject(参见“Generational GC”部分;“generational”和“ephemeral”在此上下文中是同义词。)
然而,对于int[]
阵列,它们有点神秘。我也看到了这些,并且another question here on SO关于它们的主题没有任何真正的答案。堆转储中没有引用的对象实际上并不正常,因为堆转储通常只包含活动对象(因为Hotspot在实际转储堆之前总是执行一个stop-the-world集合)。我个人的猜测是它们被分配为某种内部JVM数据结构的一部分(因此只有来自Hotspot的C ++部分而不是来自Java堆的引用),但这实际上只是一个纯粹的猜测。