问题描述
我们在调整 JVM 的内存管理时遇到问题。在 k8s 集群上运行相同的应用程序,但是其中一个 pod 的 jvm 堆使用率上升到了约 95%,并且当我们尝试在这个 vs 上获取堆转储时,不知何故 gc 运行并且堆使用率突然下降,给我们留下了微小的堆转储。
我认为旧空间不必要地增长了,并且gc没有工作来回收内存(近15个小时)。不幸的是,我们看不到什么占用了空间,因为在强制执行 gc 时,堆转储非常小。
所有 3 个 pod 的内存均为 1500m 并且 这是 jvm 堆使用百分比图(3 个 pod,绿色是有问题的一个):
详情:
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 具有广泛的与容器相关的调整选项