【问题标题】:Java application not utilizing complete heap memoryJava 应用程序未使用完整的堆内存
【发布时间】:2021-07-03 00:08:19
【问题描述】:

我使用选项 -Xmx20G 启动了我的 java 应用程序,因此它应该能够使用多达 20GB 的堆内存。我将 jVidualVm 和 JMC 连接到我的应用程序,可以看到应用程序最多只使用了 8GB 内存。 一旦内存使用量达到 8GB 左右,就会发生垃圾回收。

请看图

JMC上看到的内存使用情况,最大堆内存可以看到20GB。

知道为什么在 GC 发生之前内存使用量没有达到 20GB 左右吗?

【问题讨论】:

  • 显示 GC 日志 - 你很可能会看到发生了 Minor GC

标签: java memory memory-management heap-memory


【解决方案1】:

一个典型的Java堆分为新空间和旧空间。当新空间填满时,它会被垃圾收集。由于“大多数对象都是年轻的”,而且垃圾比非垃圾“工作量少”,所以新的空间收集器很快......

在几个新空间集合中幸存下来的对象被移动到旧空间(技术术语是“终身”)。当旧空间开始填满时,会触发旧空间收集器。旧空间收集器速度较慢,因为旧空间通常较大,那里的对象往往会在多次 GC 中幸存下来,以及其他因素。

因此,查看该图,您的 JVM 的新空间似乎约为 7GB,旧空间约为 14GB。看起来您的应用程序正在稳定地生成垃圾对象,这会反复触发新的空间收集器。但是,看起来新空间收集器成功几乎清空了新空间。 (看看图中 ar4e 中的波谷有多低。看起来它们下降到了 ~0.5MB。)

所以简短的回答是你的 20GB 堆没有被完全使用......因为它不需要被使用。对于该应用程序/工作负载来说,它的容量过大。

【讨论】:

  • 是的,看起来就是这样。应用程序生成的大多数对象都是从年轻代获取的,并通过矿工 GC 进行垃圾收集。为了确认,我用 Xmn14G 标志增加了年轻代的大小。现在正在使用高达 14G 的内存。确定这一点后,我的应用程序中的大部分内存对象都来自年轻代,我应该永久增加年轻代内存大小吗?它会提高性能,因为会发生更少的矿工 GC 吗?这是一种好的做法吗?
  • 测量它!我的直觉是,新空间可能足够大,增加它不会有太多好处。但另一方面是增加新空间可能会增加 GC 暂停(因为新空间收集是 STW),并且可能导致 GC 期间出现更多分页(因为新 GC 必须访问更多页面)。这些东西都可能是特定于应用程序的。
【解决方案2】:

尝试在命令行中添加 –XX:+DisableExplicitGC 以检查这是否会改变某些内容。

【讨论】:

  • 试过这个标志,但它没有改变任何东西。对内存的行为仍然相同。我检查了应用程序代码,我们没有在代码中的任何地方调用 System.gc()。
  • 我建议使用 JConsole 来更深入地了解内存使用情况。它允许按池查看内存利用率。正如stackoverflow.com/a/66983181/12962623 所建议的那样,您可能没有足够的长寿命对象来保存在老年代中。
  • 是的。看起来应用程序生成的大多数对象都来自年轻一代。
猜你喜欢
  • 1970-01-01
  • 2022-11-25
  • 2016-05-13
  • 2018-01-10
  • 2016-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
相关资源
最近更新 更多