JVM Optimization Learning(六)

目录

[一、JVM Optimization](#一、JVM Optimization)

1、Shenandoah

Shenandoah的使用方法

2、ZGC

内存布局

颜色指针

ZGC垃圾收集过程

ZGC的版本更迭

ZGC的使用方法

ZGC的参数设置

ZGC的调优

3、JMH测试GC性能


一、JVM Optimization

1、Shenandoah

Shenandoah是由Red Hat开发的一款低延迟的垃圾收集器,Shenandoah并发执行大部分GC工作,包括并发的整理,堆大小对STW的时间基本没有影响。

Shenandoah的使用方法

1、下载:Shenandoah只包含在OpenJDK中,默认不包含在内,需要单独构建,可以直接下载构建好的。

Shenandoah下载地址

下载选择方式如下:

1、{aarch64,arm32-hflt,mipsel,mips64el,ppc64le,s390x,x86_32,x86_64}:架构,linux中使用arch命令选择对应的架构。

javascript 复制代码
[root@localhost ~]# arch
x86_64

2、{server,zero}:虚拟机类型,选择server,包含所有GC功能

3、{release,fastdebug,Slowdebug,optimization}:不同的优化级别,选择release,性能最高。

4、{gcc*glibc*,msvc*}:编译期版本,选择较高的版本性能好一些,如果兼容性有问题,(无法启动)选择较低的版本。--glibc版本选择

javascript 复制代码
[root@localhost ~]# ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
[root@localhost ~]#

centos版本低。重新安装ubuntu操作系统22.4.3版本

javascript 复制代码
root@admin:~# ldd --version
ldd (Ubuntu GLIBC 2.35-0ubuntu3.5) 2.35
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
root@admin:~#

**我这里选择的版本:**openjdk-jdk-shenandoah-linux-x86_64-server-release-gcc10-glibc2.31.tar.xz

javascript 复制代码
root@admin:/usr/java# java -version
openjdk version "22-testing" 2024-03-19
OpenJDK Runtime Environment (build 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209)
OpenJDK 64-Bit Server VM (build 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209, mixed mode, sharing)

Linux 软件安装

2、配置。将OpenJDK配置到环境变量中,使用java -version进行测试。打印出如下内容代表成功。

javascript 复制代码
root@admin:/usr/java# java -version
openjdk version "22-testing" 2024-03-19
OpenJDK Runtime Environment (build 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209)
OpenJDK 64-Bit Server VM (build 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209, mixed mode, sharing)

3、添加参数,运行Java程序

-XX:+UseShenandoahGC 开启Shenandoah GC

-Xlog:gc 打印GC日志

2、ZGC

ZGC文章

javascript 复制代码
The Z Garbage Collector (ZGC) is a scalable low latency garbage collector. ZGC performs 
all expensive work concurrently, without stopping the execution of application threads 
for more than a millisecond. It is suitable for applications which require low latency.
Pause times are independent of the heap size that is being used. ZGC works well with 
heap sizes from a few hundred megabytes to 16TB. 

ZGC was initially introduced as an experimental feature in JDK 11, and was declared 
Production Ready in JDK 15. In JDK 21 was reimplemented to support generations.

Z垃圾收集器(ZGC)是一种可扩展的低延迟垃圾收集器。ZGC执行所有昂贵的工作都是并发的,而不会停止
应用程序线程的执行持续超过一毫秒。它适用于需要低延迟的应用程序。暂停时间与正在使用的堆大小无关。
ZGC与堆大小从几百兆字节到16TB。
ZGC最初是作为JDK 11中的一个实验特性引入的,并声明JDK 15中的生产就绪。JDK中重新实现了21,以支持几代人。

ZGC(Z Garbage Collector)是一款基于Region内存布局的,暂时不设分代的,使用了读屏障、颜色指针等技术来实现可并发的,采用标记-整理算法的,以低延迟为首要目标的一款垃圾收集器。

ZGC是一种可扩展的低延迟垃圾回收器。ZGC在垃圾回收过程中,STW的时间不会超过一毫秒,适合需要低延迟的应用。支持几百兆到16TB的堆大小,堆大小对STW的时间基本没有影响。

ZGC降低了停顿时间,能降低接口的最大耗时,提升用户体验。但是吞吐量不佳,所以如果Java服务比较关注QPS(每秒的查询次数),那么G1是比较不错的选择。

内存布局

跟G1类似,ZGC的堆内存也是基于Region来分布。不同的是,ZGC的Region支持动态地创建和销毁,并且Region的大小不是固定的,包括三种类型的Region:

Smail Region:2MB,主要用于放置小于256KB的小对象。

Medium Region:32MB,主要用于放置大于等于256KB小于4MB的对象。

Large Region:N * 2MB,这个类型的Region是可以动态变化的,不过必须是2MB的整数倍,最小支持4MB,每个Large Region只放置一个大对象,并且是不会被重分配的。

颜色指针

颜色指针,如下图所示,是ZGC的核心设计之一。以前的垃圾回收器的GC信息都保存在对象头中,而ZGC的GC信息保存在指针中。

每个对象有一个64位指针,这64位被分为:

18位:预留给以后使用。

1位:Finalizable标识。

1位:Remapped标识,是否进入了重分配集(即被移动过)。

1位:Marked1标识,简称M1。

1位:Marked0标识,和上面的Marked1都是用于辅助GC。简称M0。

42位:对象的地址(所以它可以支持2^42=4T内存)。

ZGC垃圾收集过程

大概分为4个阶段:并发标记,并发预备重分配,并发重分配,并发重映射。

并发标记(Concurrent Mark): 与G1一样,并发标记是遍历对象,做可达性分析的阶段。前后也要经过类似G1的初始标记、最终标记的短暂停顿。与G1不同的是,ZGC的标记是在指针上而不是在对象上进行的,标记阶段会更新颜色指针的M0/M1标志位。

并发预备重分配(Concurrent Prepare for Relocate): 这个阶段根据特定的查询条件统计出本次收集过程要清理哪些Region,将这些Region组成重分配集(Relocate Set)。重分配集与G1收集器的回收集(Collection Set)还是有区别的,ZGC划分Region的目的并非为了像G1那样做收益优先的增量回收。相反,ZGC每次回收都会扫描所有的Region。

并发重分配(Concurrent Relocate): 该阶段是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象到新对象的转向关系。得益于颜色指针的支持,ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配分配集之中,如果用户线程此时并发访问了位于重分配集中的对象,这次访问将被读屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象,ZGC的这种行为称作指针的"自愈"能力。

并发重映射(Concurrent Remap): 该阶段所做的主要是修正整个堆中指向重分配集中旧对象的所有引用。但是ZGC的并发重映射并不是必须要"迫切"去完成的任务。因为即使是旧引用,它也是可以自愈的,最多只是第一次使用时多一次转发和修正操作。因此,ZGC很巧妙的将并发重映射阶段要做的工作,合并到了下一次GC中的并发标记阶段里去完成,反正它们都是要遍历对象,这样就节省了一次遍历的开销。一旦所有的指针被修正之后,原来记录新旧关系的转发表就可以释放掉了。

ZGC的版本更迭

2018年JDK11,实验版本。2019年JDK12-13,并行类的卸载AArch64架构支持。

2020年JDK14-15,windows & MacOS支持第一个正式版本。

2021年JDK16-17,亚毫秒级最大暂停时间并行线程数的自动计算。

2023年JDK21,支持分代年龄。

ZGC的使用方法

OracleJDK和OpenJDK中都支持ZGC,阿里的DragonWell龙井JDK也支持ZGC但属于其自行对OpenJDK11的ZGC进行优化的版本。

建议使用JDK17之后的版本,延迟较低同时无需手动配置并行线程数。

分代ZGC添加参数启用:-XX:+UseZGC -XX:+ZGenerational

非分代ZGC通过命令行选项启用:-XX:+UseZGC

ZGC的参数设置

需要设置的参数:

-Xmx值最大堆内存大小

这是ZGC最重要的一个参数,必须设置。ZGC在运行过程中会使用一部分内存来处理垃圾回收,所以尽量保证堆中有足够的空间。设置多少值取决于对象分配的速度,根据测试情况来决定。

可以设置的参数

-XX:SoftMaxHeapSize=值

ZGC会尽量保持堆内存小于该值,这样在内存靠近这个值时会尽早地进行垃圾回收,但是依然有可能会超过该值。例如:-Xmx5g -XX:SoftMaxHeapSize=4g 这个参数设置,ZGC会尽量保证堆内存大小4GB,最多不会超过5GB。

ZGC的调优

ZGC中可以使用Linux的Huge Page大页技术优化性能,提升吞吐量、降低延迟。

注意:安装过程需要root权限,所以ZGC默认没有开启此功能。

操作步骤

1、计算所需页数,Linux x86架构中大页大小为2MB,根据所需堆内存的大小估算大页数量。比如堆空间需要16G,预留2G(JVM需要额外的一些非堆空间),那么页数就是18G/2MB=9216。

2、配置系统的大页以具有所需的页数(需要root权限)

javascript 复制代码
$ echo 9216> /sys/kernel/mm/hugepages/hugepages-2048KB/nr_hugepages

3、添加参数-XX:UseLargePages 启动程序进行测试

3、JMH测试GC性能

pom

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lwz</groupId>
    <artifactId>java_gc</artifactId>
    <version>1.0</version>

    <packaging>jar</packaging>

    <properties>
        <java.version>21</java.version>
        <sourceEncoding>UTF-8</sourceEncoding>
    </properties>

   <dependencies>
        <dependency>
           <groupId>org.openjdk.jmh</groupId>
           <artifactId>jmh-core</artifactId>
           <version>1.37</version>
        </dependency>
        <dependency>
           <groupId>org.openjdk.jmh</groupId>
           <artifactId>jmh-generator-annprocess</artifactId>
           <version>1.37</version>
        </dependency>
   </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <finalName>java_gc</finalName>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.lwz.JavaGc</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

测试代码:

java 复制代码
package com.lwz;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

//执行5轮预热,每次持续2秒
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
//输出毫秒单位
@OutputTimeUnit(TimeUnit.MILLISECONDS)
//统计方法执行的平均时间
@BenchmarkMode(Mode.AverageTime)
//java -jar xxx.jar -rf json
@State(Scope.Benchmark)
public class JavaGc {

    //每次测试对象大小4KB和4M
    @Param({"4", "4096"})
    int perSize;


    private void test(Blackhole blackhole) {

        //每次循环创建堆内存60%对象 JMX获取到Java运行中的实时数据
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
        //获取到剩余的堆内存大小
        long heapSize = (long) ((heapMemoryUsage.getMax() - heapMemoryUsage.getUsed()) * 0.6);
        //计算循环的次数
        long size = heapSize / (1024L * perSize);
        for (int i = 0; i < 4; i++) {
            List<byte[]> list = new ArrayList<>((int) size);
            for (int j = 0; j < size; j++) {
                list.add(new byte[1024 * perSize]);
            }
            blackhole.consume(list);
        }
    }

    @Benchmark
    @Fork(value = 1,jvmArgsAppend = {"-Xms4g","-Xmx4g","-XX:+UseSerialGC"})
    public void serialGc(Blackhole blackhole){
        test(blackhole);
    }

    @Benchmark
    @Fork(value = 1,jvmArgsAppend = {"-Xms4g","-Xmx4g","-XX:+UseParallelGC"})
    public void parallelGc(Blackhole blackhole){
        test(blackhole);
    }

    @Benchmark
    @Fork(value = 1,jvmArgsAppend = {"-Xms4g","-Xmx4g"})
    public void g1(Blackhole blackhole){
        test(blackhole);
    }

    @Benchmark
    @Fork(value = 1,jvmArgsAppend = {"-Xms4g","-Xmx4g","-XX:+UseShenandoahGC"})
    public void shenandoahGc(Blackhole blackhole){
        test(blackhole);
    }

    @Benchmark
    @Fork(value = 1,jvmArgsAppend = {"-Xms4g","-Xmx4g","-XX:+UseZGC"})
    public void zGc(Blackhole blackhole){
        test(blackhole);
    }

    @Benchmark
    @Fork(value = 1,jvmArgsAppend = {"-Xms4g","-Xmx4g","-XX:+UseZGC","-XX:+ZGenerational"})
    public void zGcGenerational(Blackhole blackhole){
        test(blackhole);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JavaGc.class.getSimpleName())
                .forks(1)
                .result("jmh_gc.json")
                .resultFormat(ResultFormatType.JSON)
                .build();
        new Runner(opt).run();
    }
}

打包java_gc.jar,拷贝到linux中进行测试

javascript 复制代码
root@admin:/usr/java# java -jar java_gc.jar -rf json
# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.g1
# Parameters: (perSize = 4)

# Run progress: 0.00% complete, ETA 00:12:00
# Fork: 1 of 1
# Warmup Iteration   1: 3734.047 ms/op
# Warmup Iteration   2: 1387.486 ms/op
# Warmup Iteration   3: 1737.324 ms/op
# Warmup Iteration   4: 752.472 ms/op
# Warmup Iteration   5: 2479.463 ms/op
Iteration   1: 1364.288 ms/op
Iteration   2: 1407.661 ms/op
Iteration   3: 1257.883 ms/op
Iteration   4: 1930.514 ms/op
Iteration   5: 1754.741 ms/op


Result "com.lwz.JavaGc.g1":
  1543.017 ±(99.9%) 1100.213 ms/op [Average]
  (min, avg, max) = (1257.883, 1543.017, 1930.514), stdev = 285.722
  CI (99.9%): [442.805, 2643.230] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.g1
# Parameters: (perSize = 4096)

# Run progress: 8.33% complete, ETA 00:12:54
# Fork: 1 of 1
# Warmup Iteration   1: 2989.024 ms/op
# Warmup Iteration   2: 754.789 ms/op
# Warmup Iteration   3: 815.089 ms/op
# Warmup Iteration   4: 900.940 ms/op
# Warmup Iteration   5: 819.816 ms/op
Iteration   1: 857.786 ms/op
Iteration   2: 867.094 ms/op
Iteration   3: 957.048 ms/op
Iteration   4: 845.319 ms/op
Iteration   5: 832.475 ms/op


Result "com.lwz.JavaGc.g1":
  871.945 ±(99.9%) 189.948 ms/op [Average]
  (min, avg, max) = (832.475, 871.945, 957.048), stdev = 49.329
  CI (99.9%): [681.996, 1061.893] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseParallelGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.parallelGc
# Parameters: (perSize = 4)

# Run progress: 16.67% complete, ETA 00:11:24
# Fork: 1 of 1
# Warmup Iteration   1: 4537.526 ms/op
# Warmup Iteration   2: 3549.547 ms/op
# Warmup Iteration   3: 1053.434 ms/op
# Warmup Iteration   4: 2299.266 ms/op
# Warmup Iteration   5: 2312.102 ms/op
Iteration   1: 2542.277 ms/op
Iteration   2: 2771.066 ms/op
Iteration   3: 2758.463 ms/op
Iteration   4: 2739.169 ms/op
Iteration   5: 2297.946 ms/op


Result "com.lwz.JavaGc.parallelGc":
  2621.784 ±(99.9%) 784.289 ms/op [Average]
  (min, avg, max) = (2297.946, 2621.784, 2771.066), stdev = 203.677
  CI (99.9%): [1837.495, 3406.073] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseParallelGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.parallelGc
# Parameters: (perSize = 4096)

# Run progress: 25.00% complete, ETA 00:10:35
# Fork: 1 of 1
# Warmup Iteration   1: 3772.074 ms/op
# Warmup Iteration   2: 1261.841 ms/op
# Warmup Iteration   3: 2687.961 ms/op
# Warmup Iteration   4: 2161.901 ms/op
# Warmup Iteration   5: 1239.844 ms/op
Iteration   1: 2521.028 ms/op
Iteration   2: 2741.677 ms/op
Iteration   3: 2969.740 ms/op
Iteration   4: 2845.448 ms/op
Iteration   5: 2432.363 ms/op


Result "com.lwz.JavaGc.parallelGc":
  2702.051 ±(99.9%) 859.503 ms/op [Average]
  (min, avg, max) = (2432.363, 2702.051, 2969.740), stdev = 223.210
  CI (99.9%): [1842.548, 3561.554] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseSerialGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.serialGc
# Parameters: (perSize = 4)

# Run progress: 33.33% complete, ETA 00:09:25
# Fork: 1 of 1
# Warmup Iteration   1: 5991.224 ms/op
# Warmup Iteration   2: 2589.365 ms/op
# Warmup Iteration   3: 2297.720 ms/op
# Warmup Iteration   4: 2600.618 ms/op
# Warmup Iteration   5: 2555.213 ms/op
Iteration   1: 1899.393 ms/op
Iteration   2: 2684.207 ms/op
Iteration   3: 2125.136 ms/op
Iteration   4: 1582.047 ms/op
Iteration   5: 2180.108 ms/op


Result "com.lwz.JavaGc.serialGc":
  2094.178 ±(99.9%) 1560.219 ms/op [Average]
  (min, avg, max) = (1582.047, 2094.178, 2684.207), stdev = 405.184
  CI (99.9%): [533.958, 3654.397] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseSerialGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.serialGc
# Parameters: (perSize = 4096)

# Run progress: 41.67% complete, ETA 00:08:18
# Fork: 1 of 1
# Warmup Iteration   1: 5134.703 ms/op
# Warmup Iteration   2: 2062.258 ms/op
# Warmup Iteration   3: 2039.340 ms/op
# Warmup Iteration   4: 2158.560 ms/op
# Warmup Iteration   5: 2195.067 ms/op
Iteration   1: 1504.374 ms/op
Iteration   2: 2257.207 ms/op
Iteration   3: 1489.340 ms/op
Iteration   4: 1519.162 ms/op
Iteration   5: 1821.715 ms/op


Result "com.lwz.JavaGc.serialGc":
  1718.360 ±(99.9%) 1275.601 ms/op [Average]
  (min, avg, max) = (1489.340, 1718.360, 2257.207), stdev = 331.269
  CI (99.9%): [442.759, 2993.960] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseShenandoahGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.shenandoahGc
# Parameters: (perSize = 4)

# Run progress: 50.00% complete, ETA 00:07:10
# Fork: 1 of 1
# Warmup Iteration   1: 3044.424 ms/op
# Warmup Iteration   2: 872.658 ms/op
# Warmup Iteration   3: 968.810 ms/op
# Warmup Iteration   4: 982.445 ms/op
# Warmup Iteration   5: 978.699 ms/op
Iteration   1: 984.039 ms/op
Iteration   2: 979.574 ms/op
Iteration   3: 977.392 ms/op
Iteration   4: 972.219 ms/op
Iteration   5: 976.065 ms/op


Result "com.lwz.JavaGc.shenandoahGc":
  977.858 ±(99.9%) 16.826 ms/op [Average]
  (min, avg, max) = (972.219, 977.858, 984.039), stdev = 4.370
  CI (99.9%): [961.032, 994.683] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseShenandoahGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.shenandoahGc
# Parameters: (perSize = 4096)

# Run progress: 58.33% complete, ETA 00:05:56
# Fork: 1 of 1
# Warmup Iteration   1: 27477.457 ms/op
# Warmup Iteration   2: 11334.839 ms/op
# Warmup Iteration   3: 14355.939 ms/op
# Warmup Iteration   4: 18785.548 ms/op
# Warmup Iteration   5: 15528.426 ms/op
Iteration   1: 19277.815 ms/op
Iteration   2: 16851.936 ms/op
Iteration   3: 16960.743 ms/op
Iteration   4: 17362.058 ms/op
Iteration   5: 17639.335 ms/op


Result "com.lwz.JavaGc.shenandoahGc":
  17618.377 ±(99.9%) 3772.740 ms/op [Average]
  (min, avg, max) = (16851.936, 17618.377, 19277.815), stdev = 979.769
  CI (99.9%): [13845.637, 21391.117] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseZGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.zGc
# Parameters: (perSize = 4)

# Run progress: 66.67% complete, ETA 00:05:37
# Fork: 1 of 1
# Warmup Iteration   1: 2942.659 ms/op
# Warmup Iteration   2: 716.285 ms/op
# Warmup Iteration   3: 975.803 ms/op
# Warmup Iteration   4: 728.808 ms/op
# Warmup Iteration   5: 884.607 ms/op
Iteration   1: 863.855 ms/op
Iteration   2: 716.654 ms/op
Iteration   3: 837.189 ms/op
Iteration   4: 894.194 ms/op
Iteration   5: 849.112 ms/op


Result "com.lwz.JavaGc.zGc":
  832.201 ±(99.9%) 261.922 ms/op [Average]
  (min, avg, max) = (716.654, 832.201, 894.194), stdev = 68.020
  CI (99.9%): [570.278, 1094.123] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseZGC
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.zGc
# Parameters: (perSize = 4096)

# Run progress: 75.00% complete, ETA 00:04:07
# Fork: 1 of 1
# Warmup Iteration   1: 2727.302 ms/op
# Warmup Iteration   2: 575.005 ms/op
# Warmup Iteration   3: 877.822 ms/op
# Warmup Iteration   4: 873.058 ms/op
# Warmup Iteration   5: 898.755 ms/op
Iteration   1: 727.947 ms/op
Iteration   2: 672.642 ms/op
Iteration   3: 532.763 ms/op
Iteration   4: 532.733 ms/op
Iteration   5: 531.247 ms/op


Result "com.lwz.JavaGc.zGc":
  599.466 ±(99.9%) 362.342 ms/op [Average]
  (min, avg, max) = (531.247, 599.466, 727.947), stdev = 94.099
  CI (99.9%): [237.124, 961.808] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseZGC -XX:+ZGenerational
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.zGcGenerational
# Parameters: (perSize = 4)

# Run progress: 83.33% complete, ETA 00:02:41
# Fork: 1 of 1
# Warmup Iteration   1: 4409.551 ms/op
# Warmup Iteration   2: 1083.802 ms/op
# Warmup Iteration   3: 1415.300 ms/op
# Warmup Iteration   4: 800.174 ms/op
# Warmup Iteration   5: 858.900 ms/op
Iteration   1: 807.730 ms/op
Iteration   2: 800.562 ms/op
Iteration   3: 801.663 ms/op
Iteration   4: 568.727 ms/op
Iteration   5: 659.266 ms/op


Result "com.lwz.JavaGc.zGcGenerational":
  727.590 ±(99.9%) 418.020 ms/op [Average]
  (min, avg, max) = (568.727, 727.590, 807.730), stdev = 108.558
  CI (99.9%): [309.570, 1145.610] (assumes normal distribution)


# JMH version: 1.37
# VM version: JDK 22-testing, OpenJDK 64-Bit Server VM, 22-testing-builds.shipilev.net-openjdk-jdk-shenandoah-b171-20231209
# VM invoker: /usr/java/jdk/bin/java
# VM options: -Xms4g -Xmx4g -XX:+UseZGC -XX:+ZGenerational
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
# Warmup: 5 iterations, 2 s each
# Measurement: 5 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.lwz.JavaGc.zGcGenerational
# Parameters: (perSize = 4096)

# Run progress: 91.67% complete, ETA 00:01:19
# Fork: 1 of 1
# Warmup Iteration   1: 2832.224 ms/op
# Warmup Iteration   2: 685.178 ms/op
# Warmup Iteration   3: 619.511 ms/op
# Warmup Iteration   4: 502.622 ms/op
# Warmup Iteration   5: 607.497 ms/op
Iteration   1: 675.170 ms/op
Iteration   2: 724.740 ms/op
Iteration   3: 730.490 ms/op
Iteration   4: 629.253 ms/op
Iteration   5: 667.609 ms/op


Result "com.lwz.JavaGc.zGcGenerational":
  685.453 ±(99.9%) 162.850 ms/op [Average]
  (min, avg, max) = (629.253, 685.453, 730.490), stdev = 42.292
  CI (99.9%): [522.602, 848.303] (assumes normal distribution)


# Run complete. Total time: 00:15:43

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.

NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in use. Please exercise
extra caution when trusting the results, look into the generated code to check the benchmark still
works, and factor in a small probability of new VM bugs. Additionally, while comparisons between
different JVMs are already problematic, the performance difference caused by different Blackhole
modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons.

Benchmark               (perSize)  Mode  Cnt      Score      Error  Units
JavaGc.g1                       4  avgt    5   1543.017 ± 1100.213  ms/op
JavaGc.g1                    4096  avgt    5    871.945 ±  189.948  ms/op
JavaGc.parallelGc               4  avgt    5   2621.784 ±  784.289  ms/op
JavaGc.parallelGc            4096  avgt    5   2702.051 ±  859.503  ms/op
JavaGc.serialGc                 4  avgt    5   2094.178 ± 1560.219  ms/op
JavaGc.serialGc              4096  avgt    5   1718.360 ± 1275.601  ms/op
JavaGc.shenandoahGc             4  avgt    5    977.858 ±   16.826  ms/op
JavaGc.shenandoahGc          4096  avgt    5  17618.377 ± 3772.740  ms/op
JavaGc.zGc                      4  avgt    5    832.201 ±  261.922  ms/op
JavaGc.zGc                   4096  avgt    5    599.466 ±  362.342  ms/op
JavaGc.zGcGenerational          4  avgt    5    727.590 ±  418.020  ms/op
JavaGc.zGcGenerational       4096  avgt    5    685.453 ±  162.850  ms/op

Benchmark result is saved to jmh_gc.json

生成jmh_gc.json文件,把文件上传到JMH可视化网址:JMH可视化网站​​​​​​​

上图可以看到ShenandoahGC对4MB大对象的回收效果不佳。

JVM Optimization Learning(五)

再小的努力,乘以365都很明显!
一个程序员最重要的能力是:写出高质量的代码!!
有道无术,术尚可求也,有术无道,止于术。
无论你是年轻还是年长,所有程序员都需要记住:时刻努力学习新技术,否则就会被时代抛弃!

相关推荐
武子康10 分钟前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
Captain823Jack1 小时前
nlp新词发现——浅析 TF·IDF
人工智能·python·深度学习·神经网络·算法·自然语言处理
豪宇刘1 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意1 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
Captain823Jack1 小时前
w04_nlp大模型训练·中文分词
人工智能·python·深度学习·神经网络·算法·自然语言处理·中文分词
是小胡嘛2 小时前
数据结构之旅:红黑树如何驱动 Set 和 Map
数据结构·算法
m0_748255022 小时前
前端常用算法集合
前端·算法
东阳马生架构2 小时前
JVM实战—1.Java代码的运行原理
jvm
FF在路上2 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html