JVM调优之GC调优——响应时间优先(三)

GC调优之响应时间优先

上一节简单介绍了GC调优的吞吐量优先,详见:https://blog.csdn.net/Winner941112/article/details/102679614,这一节将会考虑响应时长进行调优。

响应时间优先

依然使用之前的程序来模拟生产上的用户请求,但是改为每100毫秒创建1000线程,每个线程创建一个512kb的对象,观察GC情况,场景应该为响应时长优先。模拟代码如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 启动程序,模拟用户请求
 * 每100毫秒创建1000线程,每个线程创建一个512kb的对象,最多100毫秒内同时存在1000线程,并发量1000/s,吞吐量6000/s,查看GC的情况
 *
 */
@SpringBootApplication
public class JvmAdjust {
    public static void main(String[] args) {
        SpringApplication.run(JvmAdjust.class, args);
        System.out.println("开始启动服务..........");
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(()->{
            new Thread(()->{
                for (int i = 0; i < 1000; i++){
                    try {
                        byte[] tmp = new byte[1024 * 512];  // 专门创建512kb的小对象
                        Thread.sleep(new Random().nextInt(100));   // 随机睡眠100ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }, 100, 100, TimeUnit.MILLISECONDS);
    }
}

将程序打包上传至Linux服务器运行:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc1.log -jar classloader-jvm-2.0.7.RELEASE.jar,通过:jstat -gc -h10 $(jcmd | grep “classloader-jvm-2.0.7.RELEASE.jar” | awk ‘{print $1}’) 1000 进行实时监控,监控如图:
gc1
从图中可以看到,在10s内发生了102次YGC,耗时0.794s;发生了FullGC 1次,耗时0.039s,总gc耗时0.833s。

GC调优
1.并行收集器

1.1 使用两个线程运行程序:-XX:ParallelGCThreads=2
运行启动命令:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc2.log -XX:ParallelGCThreads=2 -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控结果如图:
gc2
从图中可以看到,在10s内发生了103次YGC,耗时0.771s;发生了FullGC 1次,耗时0.039s,总gc耗时0.809s。

1.2 增大线程数量:-XX:ParallelGCThreads=4
运行启动命令:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc3.log -XX:ParallelGCThreads=4 -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控结果如图:
gc3
从图中可以看到,在10s内发生了104次YGC,耗时0.877s;发生了FullGC 1次,耗时0.048s,总gc耗时0.925s。

1.3 减少线程数量:-XX:ParallelGCThreads=1
运行启动命令:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc4.log -XX:ParallelGCThreads=1 -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控结果如图:
gc4
从图中可以看到,在10s内发生了101次YGC,耗时0.958s;发生了FullGC 2次,耗时0.127s,总gc耗时1.085s。

2.CMS标记清除收集器

2.1 使用两个线程: java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc5.log -XX:+UseConcMarkSweepGC -XX:ConcGCThreads=2 -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控结果如图:
gc5
从图中可以看到,在10s内发生了865次YGC,耗时3.263s;发生了FullGC 23次,耗时0.19s,总gc耗时3.453s。

2.2 将线程数量增加到4个:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc6.log -XX:+UseConcMarkSweepGC -XX:ConcGCThreads=4 -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控结果如图:
gc6
从图中可以看到,在10s内发生了187次YGC,耗时1.451s;发生了FullGC 17次,耗时0.197s,总gc耗时1.648s。

2.3 将线程数量减少到1个:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc7.log -XX:+UseConcMarkSweepGC -XX:ConcGCThreads=1 -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控结果如图:
gc7
从图中可以看到,在10s内发生了1602次YGC,耗时5.637s;发生了FullGC 26次,耗时0.162s,总gc耗时5.79s。

3.G1收集器

3.1 命令参数:java -Xmx1024m -Xloggc:/usr/local/jvmtest/gc8.log -XX:+UseG1GC -jar classloader-jvm-2.0.7.RELEASE.jar,实时监控如图:
gc8
从图中可以看到,在10s内发生了80次YGC,耗时1.085s;发生了FullGC 0次,耗时0s,总gc耗时1.085s。

总结:在通过尝试不同的垃圾收集器后,发现cms垃圾收集器收集次数最频繁,用时也是最多的,而耗时最短的是默认的gc收集器。在真实的生产环境中,影响性能的问题90%以上存在于业务代码中,JVM的一些参数大多数时候是不会进行调整的,并且,gc调优是一个逐步的过程,需要尝试多次来最终决定一个合适的参数。

你可能感兴趣的:(JVM调优之GC调优——响应时间优先(三))