串行GC、并行GC、CMSGC、G1GC对堆内存的垃圾回收测试

测试代码

测试代码模拟了业务系统在单位时间内不断的创建对象,然后部分对象被回收,部分对象放入老年代。我们就可以通过打印GC日志查看不同GC垃圾回收器下的堆内存状态。

/*
演示GC日志生成与解读
*/
public class GCLogAnalysis {
    // 随机数; 记得这里可以设置随机数种子;
    private static Random random = new Random();
    public static void main(String[] args) {
        // 当前毫秒时间戳
        long startMillis = System.currentTimeMillis();
        // 持续运行毫秒数; 可根据需要进行修改
        long timeoutMillis = TimeUnit.SECONDS.toMillis(1);
        // 结束时间戳
        long endMillis = startMillis + timeoutMillis;
        LongAdder counter = new LongAdder();
        System.out.println("正在执行...");
        // 缓存一部分对象; 进入老年代
        int cacheSize = 2000;
        Object[] cachedGarbage = new Object[cacheSize];
        // 在此时间范围内,持续循环
        while (System.currentTimeMillis() < endMillis) {
            // 生成垃圾对象
            Object garbage = generateGarbage(100*1024);
            counter.increment();
            int randomIndex = random.nextInt(2 * cacheSize);
            if (randomIndex < cacheSize) {
                cachedGarbage[randomIndex] = garbage;
            }
        }
        System.out.println("执行结束!共生成对象次数:" + counter.longValue());
    }

    // 生成对象
    private static Object generateGarbage(int max) {
        int randomSize = random.nextInt(max);
        int type = randomSize % 4;
        Object result = null;
        switch (type) {
            case 0:
                result = new int[randomSize];
                break;
            case 1:
                result = new byte[randomSize];
                break;
            case 2:
                result = new double[randomSize];
                break;
            default:
                StringBuilder builder = new StringBuilder();
                String randomString = "randomString-Anything";
                while (builder.length() < randomSize) {
                    builder.append(randomString);
                    builder.append(max);
                    builder.append(randomSize);
                }
                result = builder.toString();
                break;
        }
        return result;
    }
}

串行GC

堆内存256MB
java -XX:+UseSerialGC -Xms256m -Xmx256m -XX:+PrintGCDetails GCLogAnalysis.java

  • 9个youngGC,之后一直fullGC
  • youngGC在10毫秒左右,fullGC在10毫秒左右
  • 内存不够,出现OOM

堆内存512MB
java -XX:+UseSerialGC -Xms512m -Xmx512m -XX:+PrintGCDetails GCLogAnalysis

  • 多次youngGC,1次fullGC
  • youngGC在15毫秒左右,fullGC50毫秒
  • 生成对象9727

堆内存1GB
java -XX:+UseSerialGC -Xms1g -Xmx1g -XX:+PrintGCDetails GCLogAnalysis

  • 多次youngGC
  • youngGC在30毫秒左右
  • 生成对象14916

堆内存4GB
java -XX:+UseSerialGC -Xms4g -Xmx4g -XX:+PrintGCDetails GCLogAnalysis

  • 只进行了3次youngGC
  • youngGC在80毫秒左右
  • 生成对象13590

总结:

  1. 堆内存越大,执行youngGC和fullGC的次数越少
  2. 单次youngGC和fullGC的时间随着内存的增大而增大
  3. 在堆内存为1g时,生成的对象最多

采用串行GC,随着堆内存的增大,GC的次数会减少,但是每次GC的时间会增加。

并行GC

堆内存256MB
java -XX:+UseParallelGC -Xms256m -Xmx256m -XX:+PrintGCDetails GCLogAnalysis.java

  • 10个youngGC,之后一直fullGC
  • youngGC在4毫秒左右,fullGC20毫秒左右
  • 内存不够,出现OOM

堆内存512MB
java -XX:+UseParallelGC -Xms512m -Xmx512m -XX:+PrintGCDetails GCLogAnalysis

  • 多次youngGC,多次fullGC
  • youngGC在8毫秒左右,fullGC42毫秒左右
  • 生成对象8281

堆内存1GB
java -XX:+UseParallelGC -Xms1g -Xmx1g -XX:+PrintGCDetails GCLogAnalysis

  • 多次youngGC一次fullGC
  • youngGC在15毫秒左右,fullGC50毫秒
  • 生成对象15066

堆内存4GB
java -XX:+UseParallelGC -Xms4g -Xmx4g -XX:+PrintGCDetails GCLogAnalysis

  • 只进行了4次youngGC
  • youngGC在38毫秒左右
  • 生成对象17035

总结:

  1. 堆内存越大,执行youngGC和fullGC的次数越少
  2. 单次youngGC和fullGC的时间随着内存的增大而增大
  3. 在堆内存为越大,生成对象越多
  4. 采用并行GC比串行GC每次GC的时间更少

CMSGC

堆内存256MB
java -XX:+UseConcMarkSweepGC -Xms256m -Xmx256m -XX:+PrintGCDetails GCLogAnalysis.java

  • 9个youngGC,
  • youngGC在10毫秒左右,fullGC在30毫秒左右
  • 生成对象4329

堆内存512MB
java -XX:+UseConcMarkSweepGC -Xms512m -Xmx512m -XX:+PrintGCDetails GCLogAnalysis

  • 多次youngGC,多次fullGC
  • youngGC在12毫秒左右,fullGC在57毫秒左右
  • 生成对象11254

堆内存1GB
java -XX:+UseConcMarkSweepGC -Xms1g -Xmx1g -XX:+PrintGCDetails GCLogAnalysis

  • 多次youngGC,多次fullGC
  • youngGC在15毫秒左右,fullGC在60毫秒左右
  • 生成对象15820

堆内存4GB
java -XX:+UseConcMarkSweepGC -Xms4g -Xmx4g -XX:+PrintGCDetails GCLogAnalysis

  • 只进行了6次youngGC
  • youngGC在50毫秒左右
  • 生成对象15145

总结:

  1. 堆内存越大,执行youngGC和fullGC的次数越少
  2. 单次youngGC和fullGC的时间随着内存的增大而增大
  3. 在堆内存为越大,生成对象越多

G1GC

堆内存256MB
java -XX:+UseG1GC -Xms256m -Xmx256m -XX:+PrintGCDetails GCLogAnalysis.java

  • 内存不够,出现OOM
  • GC时间1.6ms左右

堆内存512MB
java -XX:+UseG1GC -Xms512m -Xmx512m -XX:+PrintGCDetails GCLogAnalysis

  • GC时间1.3ms左右
  • 生成对象11284

堆内存1GB
java -XX:+UseG1GC -Xms1g -Xmx1g -XX:+PrintGCDetails GCLogAnalysis

  • GC时间3.2ms左右
  • 生成对象14569

堆内存4GB
java -XX:+UseG1GC -Xms4g -Xmx4g -XX:+PrintGCDetails GCLogAnalysis

  • GC时间8.7ms左右
  • 生成对象16853

总结:

  1. 堆内存越大,越适合用G1GC
  2. 在堆内存为越大,生成对象越多

如何选择GC

选择正确的GC算法,唯一可行的方式就是去尝试,一般性的指导原则:

  • 如果系统考虑吞吐优先,CPU资源都用来最大程度处理业务,用Parallel GC。
  • 如果系统考虑低延迟有限,每次GC时间尽量短,用CMS GC。
  • 如果系统内存堆较大,同时希望整体来看平均GC时间可控,使用G1 GC。

对于内存大小的考量:

  • 一般4G以上,算是比较大,用G1的性价比较高。
  • 一般超过8G,比如16G-64G内存,非常推荐使用G1 GC。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值