【问题标题】:The Java ZGC garbage collector USES a lot of memoryJava ZGC 垃圾收集器使用大量内存
【发布时间】:2020-11-05 15:32:13
【问题描述】:

我使用 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

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

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

【问题讨论】:

    标签: java jvm java-11 zgc


    【解决方案1】:

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

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

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

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

    另见:

    【讨论】:

    【解决方案2】:

    JVM 使用的不仅仅是堆内存 - 阅读这个出色的答案以更好地了解 JVM 内存消耗:Java using much more memory than heap size (or size correctly Docker memory limit)

    您需要超越堆检查并使用Native Memory Tracking 之类的东西来获得更清晰的画面。

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

    【讨论】:

      【解决方案3】:

      这是 throughput-latency-footprint 权衡的结果。在这 3 件事之间进行选择时,您只能选择 2。

      ZGC 是具有低暂停次的并发 GC。由于您不想放弃吞吐量,因此您可以用延迟和吞吐量换取占用空间。所以,如此高的内存消耗也就不足为奇了。

      G1 不是低暂停收集器,因此您将权衡转移到占用空间并获得更长的暂停时间但赢得一些内存。

      【讨论】:

      • 操作系统报告的内存使用情况并不能反映带有 ZGC 的 JVM 实际使用了多少 RAM(~1/3 所示的虚拟内存大小)。请参阅上面的@apangin 答案。
      【解决方案4】:

      JVM 使用的操作系统内存量(即“已提交堆”)取决于 GC 运行的频率(以及如果应用开始使用较少的内存,它是否取消提交不需要的内存),这是一个可调选项。不幸的是,ZGC 默认情况下(目前)并不像 G1 那样积极,但两者都有一些tuning options that you can try

      附:正如其他人所指出的,RES htop 列具有误导性,但 VisualVM 图表显示了真实情况。

      【讨论】:

        猜你喜欢
        • 2019-02-08
        • 2014-03-31
        • 2012-06-12
        • 2019-09-14
        • 2011-11-07
        • 2017-03-15
        • 1970-01-01
        • 2012-06-28
        • 2016-11-02
        相关资源
        最近更新 更多