You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenJDK 17中G1GC、PGC大堆内存下存储能力退化问题咨询

问题分析:G1GC/PGC大堆内存下对象存储量退化现象

实验背景

  • 实验目的:探究JVM堆内存大小变化时的对象存储行为
  • 堆内存范围:1GB ~ 100GB
  • 测试收集器:G1GC、ZGC、PGC
  • 核心现象:G1GC和PGC在堆内存超过32GB后,可存储的Entity对象数量随堆内存增大反而减少;ZGC无此问题

测试代码

public class Memory {
    // Dummy Entity representing usual data objects
    private static class Entity {
        public String name;
        public String detail;
        public Double amount;
        public Integer age;
    }

    // Linked list offers table inserts and helps illustrating the issue by using multiple
    // references per entry
    public static java.util.LinkedList<Entity> entities = new java.util.LinkedList<>();

    // This threshold should be 2 times Xmn. It ensures the loop stops before a full GC happens.
    private static final int MB = 1024 * 1024;
    private static final int THRESHOLD = 100 * MB;

    public static void main(String[] args) {
        System.out.println("Total Memory (in bytes): " + Runtime.getRuntime().totalMemory());
        System.out.println("Free Memory (in bytes): " + Runtime.getRuntime().freeMemory());
        System.out.println("Max Memory (in bytes): " + Runtime.getRuntime().maxMemory());

        while (true) {
            appendEntitiesToDataStructure();
            terminateBeforeFullGCorOOMEcanHappen();
        }
    }

    private static void appendEntitiesToDataStructure() {
        entities.add(new Entity());
    }

    private static void terminateBeforeFullGCorOOMEcanHappen() {
        if (Runtime.getRuntime().freeMemory() < THRESHOLD) {
            System.out.println("Elements created and added to LinkedList: " + entities.size());
            System.exit(0);
        }
    }
}

启动命令

java -Xms${i}g -Xmx${i}g -Xmn50m memory.java >> output.txt

退化现象原因分析

1. G1GC/PGC的指针压缩机制限制

JVM默认启用指针压缩(Compressed Ordinary Object Pointers, Compressed Oops),将64位指针压缩为32位,减少内存开销并提升性能。但该机制的有效寻址上限为32GB(精确值为32GB-1字节):

  • 当堆内存超过32GB时,G1GC和PGC会自动禁用指针压缩,所有对象指针从4字节扩容为8字节
  • Entity类包含多个引用类型字段,加上LinkedList节点的前后指针,指针扩容直接增加了每个对象的内存占用
  • 同时JVM内部元数据、GC相关结构也会因指针膨胀占用更多堆内存,留给业务对象的可用空间增幅远低于堆内存扩容幅度,最终导致可存储的Entity数量不增反降

2. ZGC的架构优势

ZGC从设计上摆脱了对指针压缩的依赖:

  • 它采用**着色指针(Colored Pointers)**和内存映射技术,即便在TB级超大堆下也能保持高效寻址
  • 无论堆内存多大,ZGC无需切换指针大小,对象内存占用稳定,堆内存扩容后可用空间能线性提升,因此不会出现存储量退化现象

3. 固定新生代配置的放大效应

你设置的-Xmn50m(新生代固定50MB)进一步放大了问题:

  • 堆超过32GB时,老年代占比极高,G1/PGC的老年代区域划分(如G1的Region)、GC根节点扫描等开销会因指针膨胀大幅增加,进一步挤占业务对象的内存空间

内容的提问来源于stack exchange,提问作者sacha.p

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:05:16