---
title: 2021年毕昇 JDK 的第一个重要更新来了-官方技术文章-鲲鹏社区
description: 本文主要介绍G1 Full GC优化原理及使用，LazyBox 特性介绍，鲲鹏硬件加速的KAEProvider，Jmap 并发扫描介绍等相关内容。
keywords: 年毕昇,JDK,的第一个重要更新来了,官方技术文章,鲲鹏社区,Full,GC,优化原理及使用
url: https://www.hikunpeng.com/developer/techArticles/20230901-3?envFlag=1
section: (其他)
---

# 2021年毕昇 JDK 的第一个重要更新来了-官方技术文章-鲲鹏社区

URL: https://www.hikunpeng.com/developer/techArticles/20230901-3?envFlag=1
描述: 本文主要介绍G1 Full GC优化原理及使用，LazyBox 特性介绍，鲲鹏硬件加速的KAEProvider，Jmap 并发扫描介绍等相关内容。
关键词: 年毕昇,JDK,的第一个重要更新来了,官方技术文章,鲲鹏社区,Full,GC,优化原理及使用

官方技术文章 [了解详情](https://www.hikunpeng.com/zh/developer/techArticles)

2021年毕昇 JDK 的第一个重要更新来了

2021年毕昇 JDK 的第一个重要更新来了

实战经验

发表于 2021/04/15

0

2021 年 3 月 31 日，毕昇 JDK update 版本正式发布，下载方式见文末参考文档[1][2]，该版本在同步 OpenJDK 社区 8u282/11.0.10 的基础上，还包含如下更新，为用户提供高性能、可用于生产环境的 OpenJDK 发行版。

（1）G1 Full GC 优化(毕昇 JDK 11)

（2）LazyBox 特性(毕昇 JDK 11)

（3）提供鲲鹏硬件加速的 KAEProvider(毕昇 JDK 8)

（4）map 并发扫描优化(毕昇 JDK8, 毕昇 JDK11)

（5）Bug fixes

## G1 Full GC 优化原理及使用

G1 GC(Garbage First Garbage Collector)是一款面向服务端、低延迟的垃圾收集器.当 G1 进行 Full GC 时，会对整个堆进行清理，耗时较长，所以如何调优 Full gc 一直是开发人员奋斗的目标之一。G1 Full GC 在当前的实现中，主要包括如下四个阶段：标记存活对象、计算目标对象的位置、更新引用的位置、移动对象完成压缩，由于 G1 对存活对象较多的 region 进行回收时(G1 是以 region 为单位来管理 java 堆的)，需要移动较多的对象，却只能回收较少的内存，效率低下，因此可以在 G1 的第四阶段不对此 region 进行压缩，减少处理的时间。

### 1. 优化原理

针对上面这种情况，可以通过如下步骤，对 Full GC 过程进行优化：

（1）在标记阶段，对每个 region 存活的字节数进行统计

（2）在计算目标对象位置时，把存活比例较高的 region 加入到不进行压缩的 region 集合

（3）更新引用的位置与现有情况保持一致

（4）在压缩时跳过不进行压缩的 region 集合 为此，我们为用户提供如下参数来使用该特性：

| 参数 | 说明 |
| --- | ---|
| G1FullGCNoMoving | 打开选项后，当 G1 进行 Full GC
  时，将会启用此优化功能。此选项默认|
| G1NoMovingRegionLiveBytesLowerThreshold | 指定不进行压缩的 region
  中存活字节占比的最小值。即当 region 中的存活字节数占比超过设定的值时，将该 region 加入到不进行压缩的 region 集合。默认值为 98 |

在存活对象占比较高的 Full GC 中，使用此特性将会减少 Full GC 的停顿时间。

### 2. 性能测试

Dacapo 是一种可以对编程语言、内存管理和计算机体系结构进行测试的 Java 基准测试工具，由以下套件组成：avrora、batik、eclipse、fop、h2、jython、pmd、tomcat、daytrader、xalan、lucene 等，其中 h2 是一种类似于 JDBCbench 的内存基准测试，针对银行应用程序的模型执行许多事务，详见[3]。这里对 h2 进行测试。

测试环境：

（1）CPU: Kunpeng 920

（2）OS: CentOS 7.6

（3）JDK: 毕昇 JDK 11.0.10

测试脚本 script.sh 如下，执行./script.sh h2,然后即可统计 Full GC 停顿时间。

```
#!/bin/bash
export java=$JAVA_HOME/bin/java
export java_options="-Xmx1g -Xms1g -XX:ParallelGCThreads=4"
echo $java $java_options

task=$1
for i in `seq 30`
do
  echo ">>>>>>>>>>>>>>>>>>>> base $i <<<<<<<<<<<<<<<<<<<<<<"
  $java $java_options -Xlog:gc*=info:file=h2-base/gc-$task-base-$i.log -jar dacapo-9.12-bach.jar -t 4 --iterations 5 --size huge --no-pre-iteration-gc $task
done
for i in `seq 30`
do
  echo ">>>>>>>>>>>>>>>>>>>> opt $i <<<<<<<<<<<<<<<<<<<<<<"
  $java $java_options -XX:+G1FullGCNoMoving -Xlog:gc+phases=trace,gc=info,gc+heap=info,gc+task=info:file=h2-opt/gc-$task-opt-$i.log -jar dacapo-9.12-bach.jar -t 4 --iterations 5 --size huge --no-pre-iteration-gc $task
done
```

测试结果：其中 Percentile 为箱线图中的概念，10% 即表示将数据从小到大排序，第 10%个数据提升 11.25%.

测试结果

结论：从图中可以看到，优化之后可以将 G1 Full GC 的停顿时间降低 3%~11%。

该优化的一部分已合入 OpenJDK 社区[4],剩余部分正在推进中。

## LazyBox 特性介绍

Java 为每种基本类型提供了对应的包装类型，将基本类型转换为包装类型在 Java 中称为装箱。由于泛型的存在，在 Java 中会频繁的进行装箱拆箱操作，带来许多额外的开销，典型例子如下：

```
<T extends Number>
int add(T a, T b) {
  return a.intValue() + b.intValue();
}
```

LazyBox 特性通过在 Hotspot C2 中推迟装箱的时机，使 C2 只进行必要的装箱，减少装箱操作，提高 C2 生成代码的执行效率。

### 1. 场景分析

对于某些装箱后的值，在某些路径下并不会被用到，但还是会忍受装箱带来的开销。比如下面代码中的 integer 对象：

```
 int sum = 0;
  for (int i = 0; i < 100; i++) {
    Integer integer = Integer.valueOf(299);
        if (i < 1) {  //冷路径
             blackhole.consume(integer); //逃逸
             sum+=2;
        } else {     //热路径
             sum+=integer.intValue(); //拆箱
        }
  }
  return sum;
```

当 i>=1 时，代码只是想获取 integer 对象的 int 值，此时没有必要对 integer 进行装箱，在此中场景下，使用 LazyBox 可以极大的提高性能。只有等到确实需要装箱时，再在 C2 中插入装箱操作。

不过由于在每次需要装箱时，都会插入装箱操作，所以在某些场景下可能会导致对象不一致。例如下面的场景：

```
Data data = new Data();

int value = 299;
Integer a = Integer.valueOf(value);
data.a = a;
data.b = a;

System.out.println(data.a == data.b); //开启LazyBox后为false
```

由于将 a 赋值给 data 中的 a 和 b 之前，都在 C2 中插入了装箱操作，所以导致 data 中的 a 和 b 为不同的对象，所以在使用 LazyBox 时，用户需要留心这一点。

相关参数如下：

| 参数 | 说明 |
| --- | ---|
| LazyBox | 打开 LazyBox
  特性，该选项为实验选项，需要开启-XX:+UnlockExperimentalVMOptions， 同时由于 LazyBox 依赖
  AggressiveUnBoxing 优化，所以还需开启-XX:+AggressiveUnboxing 选项 |
| PrintLazyBox | 打印 LazyBox 状态，用于开发者调试 |

用户可通过如下方式使用 LazyBox 特性:

```
-XX:+UnlockExperimentalVMOptions -XX:+AggressiveUnboxing -XX:+LazyBox
```

### 2. 性能测试

测试环境：

（1）CPU: Kunpeng 920

（2）OS: openEuler 20.03

（3）JDK: 毕昇 JDK 11.0.10

本实验采用工业级测试套件 SPECPower 进行测试，在测试过程中进行了绑核，测试结果表明：结合 毕昇 JDK 以前的优化，相比 OpenJDK 可以提升 SPECPower 10%.

## 鲲鹏硬件加速的 KAEProvider

KAE（Kunpeng Accelerate Engine）加解密是鲲鹏 920 处理器提供的硬件加速方案，可以显著降低处理器消耗，提高处理器效率[5].毕昇 JDK 为 Java 用户提供 KAEProvider，使 Java 开发人员可以直接使用硬件带来的加速效果，提升加解密效率。

### 1. 实现

Java 通过 JCA(Java Cryptography Architecture)为开发者提供了良好的接口，开发者只需要实现 SPI(Service Provider Interface)接口，并在 CSP(Cryptographic Service Provider, 下文简称 Provider)中进行注册，即可让用户使用自己的加解密实现。举个例子：当用户通过MessageDigest.getInstance("SHA-256")获取 message digest 对象时，JCA 会依次搜索注册的 Provider，直到找到一种实现为止，大体过程如下[6]：

用户可通过 java.security 文件指定各个 Provider 的优先级，或者在代码中通过Security.insertProviderAt(Provider, int)接口指定.也可以在获取摘要对象时手动指定从哪个 Provider 中获取，如MessageDigest.getInstance("SHA-256","KAEProvider"),这种情况下，JCA 将优先使用用户指定的 Provider.

毕昇 JDK 当前实现了 MessageDigest(MD5,SHA256,SHA384)、Cipher(AES-ECB,AES-CBC,AES-CTR,RSA)、KeyPairGenerator(RSA)、HMac 等 SPI，并在 KAEProvider 中进行了注册，其它算法会在后续版本合入，用户可通过如下方式来使用 KAEProvider.

（1）方式 1: 使用 Security API 添加 KAE Provider ，并设置其优先级。

```
Security.insertProviderAt(new KAEProvider(), 1);
```

（2）方式 2:修改 jre/lib/security/java.security 文件，添加 KAE Provider，并设置其优先级。

```
security.provider.1=org.openEuler.security.openssl.KAEProvider
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC
security.provider.11=sun.security.mscapi.SunMSCAPI
```

### 2. 性能测试

JMH(Java Microbenchmark Harness)是 OpenJDK 社区提供的一种对 Java 进行 benchmark 测试的工具，使用方式见[7].毕昇 JDK 已将对应的 JMH 测试用例合入了 openEuler 社区[8],这里采用对应的用例进行测试。

测试环境：

（1）CPU: Kunpeng 920

（2）OS: openenuler 20.03

（3）KAE: v1.3.10 ,下载链接见[9]

（4）JDK: 毕昇 JDK 1.8.0_282

测试结果如下，可以看到，在使用 KAEProvider 后，RSA 加解密性能明显提升。

测试结果

结论：相比 JDK 默认 Provider 提供的 RSA 加解密，当密钥长度为 2048 位时，KAEProvider 可以提升 53%~80%，当密钥长度为 4096 位时，KAEProvider 可以提升 70%~83%。

## Jmap 并发扫描介绍

当前 jmap 采用单线程对 java 堆进行扫描，扫描速度较慢，并且当对超大堆进行扫描时（大于 200G），容易引起系统卡死。因此可以通过多线程来进行扫描，减少卡顿时间。

### 实现

毕昇 JDK 将社区高版本的 jmap 优化回合到此次发布中,为 jmap -histo 选项增加指定并发线程数的 parallel 参数，使 jmap 可以使用多线程对堆进行扫描，有效提高 jmap 的扫描效率，减少扫描时间。具体实现原理可参考[10]。用户可通过在 jmap -histo 后增加 parallel 参数来使用此特性，如下所示：

（1）jmap -histo:live,parallel=3 pid : 指定并发线程数为 3

（2）jmap -histo:live,parallel=0 pid : 使用当前系统可支持的并发线程数（-XX:ParallelGCThreads）

（3）jmap -histo:live,parallel=1 pid : 使用原有的串行扫描

当前的实现只支持 G1 和 ParallelGC，后续版本将支持 CMS.

## Bug fixes

除了上面介绍的一些特性外，毕昇 JDK 还合入了社区高版本中的一些 bug fix 和优化的 patch，为用户提供稳定、高性能的毕昇 JDK。具体回合 patch 如下：

（1）JDK8

a. 8231841: AArch64: debug.cpp help() is missing an AArch64 line for pns

b. 8254078: DataOutputStream is very slow post-disabling of Biased Locking

c. 8168996: C2 crash at postaloc.cpp

d. 8140597: Forcing an initial mark causes G1 to abort mixed collections

e. 8214418: half-closed SSLEngine status may cause application dead loop

f. 8259886: Improve SSL session cache performance and scalability

（2）JDK11

a. 8254078: DataOutputStream is very slow post-disabling of Biased Locking

b. 8217918: C2: -XX:+AggressiveUnboxing is broken

## 参考

[1] Bishengjdk8下载：https://mirrors.huaweicloud.com/kunpeng/archive/compiler/bisheng_jdk/bisheng-jdk-8u282-linux-aarch64.tar.gz [了解详情](https://mirrors.huaweicloud.com/kunpeng/archive/compiler/bisheng_jdk/bisheng-jdk-8u282-linux-aarch64.tar.gz)

[2] Bishengjdk11下载：https://mirrors.huaweicloud.com/kunpeng/archive/compiler/bisheng_jdk/bisheng-jdk-11.0.10-linux-aarch64.tar.gz [了解详情](https://mirrors.huaweicloud.com/kunpeng/archive/compiler/bisheng_jdk/bisheng-jdk-11.0.10-linux-aarch64.tar.gz)

[3] dacapo介绍：http://dacapobench.org/ [了解详情](http://dacapobench.org)

[4] 8263495: Gather liveness info in the mark phase of G1 full gc：https://github.com/openjdk/jdk/commit/8c8d1b31 [了解详情](https://github.com/openjdk/jdk/commit/8c8d1b31)

[5] 鲲鹏加速引擎介绍：https://www.hikunpeng.com/document/detail/zh/kunpengboostkithistory/250RC1/accel/kunpengaccel_16_0002.html [了解详情](https://www.hikunpeng.com/document/detail/zh/kunpengboostkithistory/250RC1/accel/kunpengaccel_16_0002.html)

[6] Java Cryptography Architecture (JCA) Reference Guide：https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html [了解详情](https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html)

[7] jmh介绍：https://github.com/openjdk/jmh [了解详情](https://github.com/openjdk/jmh)

[8] KAEProvider jmh用例：https://gitcode.com/openeuler/bishengjdk-8/tree/master/jdk/test/micro/org/openeuler/bench/security/openssl [了解详情](https://gitcode.com/openeuler/bishengjdk-8/tree/master/jdk/test/micro/org/openeuler/bench/security/openssl)

[9] KAE下载链接：https://github.com/kunpengcompute/KAE/releases [了解详情](https://github.com/kunpengcompute/KAE/releases)

[10] 8239290:Add parallel heap iteration for jmap -histo：https://bugs.openjdk.java.net/browse/JDK-8239290 [了解详情](https://bugs.openjdk.java.net/browse/JDK-8239290)

本页内容
