JConsole堆转储比内存使用量小得多

时间:2019-04-22 13:56:58

标签: java linux spring-boot

我们有一些容器通过docker运行Java进程。我们注意到的一件事是,仅通过运行一个简单的spring-boot应用程序就占用了大量内存,甚至不包含我们自己的代码(只是尝试获取某种内存配置文件,而与我们可能引入的任何问题无关) )。

我看到的是docker / JVM消耗的内存徘徊在2.5左右。我们确实包含了相当多的额外部门(骆驼,冬眠,一些春季靴子部门),但这并不是真正让我失望的东西。我看到的是,尽管Docker表示它已为该应用程序消耗了2.5GB的内存,但对它运行jconsole却显示它消耗了多达1GB的内存(GC并缓慢攀升后降至约200MB)。泊坞窗上的内存空间也保持在GC之后的水平(2.5GB)。

此外,当我转储堆以查看哪些对象正在占用该空间时,将.hprof文件加载到MAT中后,堆看起来只有33MB。这些对我来说都没有多大意义。目前,我正在查看jconsole中报告的非堆空间为115MB,而堆空间为331MB。

我(在SO和其他站点上)已经读了很多关于JVM内存区域的信息,并且有些事情专门报告说堆转储可能较小,但是我所能说的都不远,建议要注意的许多事情是,每当进行堆转储时,GC都会运行,并且MAT具有显示或隐藏无法访问的对象的设置。在发布到这里之前,已经考虑了所有这些问题,现在我感觉好像有其他事情在起作用,我无法捕捉自己,也没有在网上找到。

我完全希望数字可能会有些许偏离,但在最佳情况下,它们似乎相差十倍,而在查看docker报告的内存使用情况时,相差近一百倍。

有人知道我在这里可能会想念什么吗?

编辑:这也是一个运行Java 8的应用程序,尚未运行Java11。它在JIRA板上可以执行,但尚未计划。

EDIT2:添加屏幕截图。 JConsole屏幕截图中的峰值来自于运行GC。

Docker Stats with memory usage

JConsole heap memory usage

MAT heap dump

2 个答案:

答案 0 :(得分:2)

JConsole为您提供了已落实的内存量:3311616 KiB〜= 3GiB 如操作系统所见,这是Java进程消耗的内存量。

这与当前用于容纳Java对象的堆大小无关,JConsole也将其报告为130237 KB〜= 130 MiB。

这也与实际存在的对象数无关:默认情况下,当您加载堆转储时,MAT将删除无法访问的对象。您可以通过转到首选项->内存分析器->保留无法访问的对象来启用该选项(请参见the MAT documentation)。因此,如果您有很多短暂的对象,那么差异可能会很大。

我看到它还报告了大约9GiB的最大堆。这意味着您已将Xmx参数设置为较大的值。

热点GC在回收未使用的内存方面不是很好。他们倾向于使用所有可用的空间(最大堆大小,由Xmx设置),然后从不取消使用堆,从而有效地将其保留给Java进程使用,而不是释放给操作系统。

如果要从OS角度最小化进程的内存占用,我建议您设置较低的Xmx,也许是-Xmx1g,以免Java增长太多(当然,Xmx也需要足以容纳您的应用程序工作量!)。

如果确实需要自适应堆,那么您也可以切换到G1(-XX:+ UseG1GC)和更新的Java,因为热点团队最近已经交付了some improvements

答案 1 :(得分:0)

戴夫

OS监视工具将向您显示进程分配的内存量。所以这:  enter image description here 意味着您的Java进程分配了2.664G的内存(Java堆+元空间)

JConsole向您显示内存中您的代码正在“消耗”(忽略元空间)

我看到2种可能的解释:

  1. 您为-Xms设置了巨大的价值
  2. 您有很多静电     代码(或其他内容)加载到您的元空间中。
相关问题