Java ZGC 垃圾回收器使用大量内存

2022-09-04 07:18:52

我使用Springboot构建了一个简单的应用程序。我在部署到Linux服务器时使用的ZGC垃圾回收器使用了大量的内存。我试图使用Xmx500m将最大堆内存限制为500MB,但JAVA程序仍然使用超过1GB。当我使用G1收集器时,它只使用了350MB。我不知道为什么,这是JDK11的错误吗?或者我的引导参数有问题吗?####Runtime环境

  • 操作系统CentOS Linux 版本 7.8.2003
  • JDK 版本jdk11
  • springboot 版本v2.3.0.RELEASE 这是我的 Java 启动命令
java -Xms128m -Xmx500m \
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC \
-jar app.jar

下面是运行时内存使用情况的屏幕截图

堆内存使用情况 https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20201259.png?raw=true

系统内存使用 https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20201357.png?raw=true


下面是使用缺省垃圾回收器 Java 启动命令时发生的情况

java -Xms128m -Xmx500m \
-jar app.jar

堆内存使用情况 https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20202442.png?raw=true

系统内存使用情况 https://github.com/JoyfulAndSpeedyMan/assets/blob/master/2020-07-13%20202421.png?raw=true

默认情况下,jdk11 使用 G1 垃圾回收器。从理论上讲,G1不应该比ZGC更占用内存吗?我为什么不这样使用它?我误会了吗?由于我是JVM的初学者,我不明白为什么。


答案 1

ZGC 采用一种称为彩色指针的技术。这个想法是使用64位指针中的一些可用位到堆中用于嵌入的元数据。但是,在取消引用此类指针时,需要屏蔽这些位,这意味着 JVM 需要做一些额外的工作。

为了避免屏蔽指针的开销,ZGC 涉及多映射技术。多映射是指将多个虚拟内存范围映射到同一物理内存范围。

ZGC 使用 3 个 Java 堆视图(“marked0”、“marked1”、“重新映射”),即 3 种不同的堆指针“颜色”和 3 个用于同一堆的虚拟内存映射。

因此,操作系统可能会报告 3 倍大的内存使用量。例如,对于 512 MB 堆,报告的已提交内存可能高达 1.5 GB,不计算堆以外的内存。注意:多映射会影响报告的已用内存,但从物理上讲,堆仍将在 RAM 中使用 512 MB。这有时会导致一个有趣的效果,即该过程的RSS看起来大于物理RAM的数量

另请参阅:


答案 2

JVM使用的不仅仅是堆内存 - 阅读这个出色的答案以更好地了解JVM内存消耗:Java使用的内存远远超过堆大小(或正确的大小Docker内存限制)

您需要超越堆检查,并使用本机内存跟踪之类的东西来获得更清晰的图像。

我不知道您的应用程序有什么特别的问题,但 ZGC 经常被提及为适用于大型堆。它也是一个全新的收集器,最近有很多变化 - 如果你想使用它,我会升级到JDK 14(请参阅这里的“更改日志”:https://wiki.openjdk.java.net/display/zgc/Main)


推荐