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

gre*_*lf 6 java jvm java-11 zgc

我使用Springboot构建了一个简单的应用程序。我在部署到Linux服务器时使用的ZGC垃圾收集器使用大量内存..我尝试使用Xmx500m将最大堆内存限制为500MB,但JAVA程序仍然使用了1GB以上。我用G1收集器的时候只用了350MB。不知道为什么,这是JDK11的BUG吗?还是我的启动参数有问题?####运行环境

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

这是运行时内存使用情况的截图

堆内存使用情况 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
Run Code Online (Sandbox Code Playgroud)

堆内存使用情况 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的初学者,我不明白为什么。

apa*_*gin 15

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

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

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

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

也可以看看:

  • @JurajMartinka 不仅在容器中。容器的问题是,一旦达到容器配额,操作系统就会终止该进程。 (2认同)
  • 有关相关讨论,请参阅 https://mail.openjdk.java.net/pipermail/zgc-dev/2018-November/000540.html。 (2认同)

Jur*_*nka 2

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

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

我不知道您的应用程序有什么特殊问题,但经常提到 ZGC 对于大型堆很有用。它也是一个全新的收集器,最近进行了许多更改 - 如果您想使用它,我会升级到 JDK 14(请参阅此处的“更改日志”:https: //wiki.openjdk.java.net/display/zgc/Main