堆转储和不必要的堆使用的 JVM GC 行为

问题描述

我们在调整 JVM 的内存管理时遇到问题。在 k8s 集群上运行相同的应用程序,但是其中一个 pod 的 jvm 堆使用率上升到了约 95%,并且当我们尝试在这个 vs 上获取堆转储时,不知何故 gc 运行并且堆使用率突然下降,给我们留下了微小的堆转储。

我认为旧空间不必要地增长了,并且gc没有工作来回收内存(近15个小时)。不幸的是,我们看不到什么占用了空间,因为在强制执行 gc 时,堆转储非常小。

所有 3 个 pod 的内存均为 1500m 并且 这是 jvm 堆使用百分比图(3 个 pod,绿色是有问题的一个):

JVM Heap Usage

详情:

openjdk 15.0.1 2020-10-20
OpenJDK Runtime Environment AdoptOpenJDK (build 15.0.1+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 15.0.1+9,mixed mode,sharing)

JVM 参数:

-XX:MaxRAMPercentage=75
-XX:InitialRAMPercentage=75
-server
-Xshare:off
-XX:MaxMetaspaceSize=256m
-Dsun.net.inetaddr.ttl=60
-XX:-OmitStackTraceInFastThrow
-XX:+ShowCodeDetailsInExceptionMessages

问题是:

  • 为什么在我们尝试获取堆转储时会调用完整的 gc?
  • gc 不回收内存并导致应用程序运行时堆大小在约 70% 到约 95% 之间的动机是什么,而 jvm 可以使用并且仅在 10% 时完美运行?
  • 如何强制 jvm 更积极地执行 gc 以避免这种情况?还是应该在生产环境中完成?

解决方法

JVM 堆转储过程有两种模式

  • 活动对象 - 此模式与堆转储一起执行 Full GC。这是默认选项。
  • 所有对象 - 堆转储将包括堆上可到达和不可到达的所有对象。

堆转储模式通常可以通过工具特定选项进行选择。

回答您的问题

为什么在我们尝试获取堆转储时会调用完整的 gc?

以上已回答

gc 不回收内存并导致应用程序运行时堆大小在 ~70% 到 ~95% 之间的动机是什么,而 jvm 可以使用并且只有 10% 才能完美工作?

回收内存需要 CPU 资源并影响应用程序延迟。当 JVM 在内存限制下运行时,它主要会避免昂贵的 GC。

最近容器的发展推动了 JVM GC 部门的一些变化,但上述声明仍然与默认 GC 配置相关。

有什么办法可以强制jvm更积极地做gc来避免这种情况?还是应该为生产环境做?

原始答案缺少问题陈述。但一般建议是

  • 管理每个容器的内存限制(JVM 从容器限制派生堆大小,除非它们被明确覆盖)
  • 定期强制 GC 是可能的,但不太可能解决任何问题
  • G1GC 具有广泛的与容器相关的调整选项

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...