Java 27正式发布:G1成默认垃圾收集器,新增抗量子TLS
本文最先发表于我的个人博客:Java 27:有哪些新变化?,并且是关于 Java 最新版本有哪些新变化系列文章的一部分。
既然 Java 27 已经发布,现在就来逐一看看这个新版本为我们开发者带来的所有功能。
在 Java 26 及其 10 个 JEP 之后,Java 27 只带来了少量 JEP——9 个,新功能也非常少。
JEP 523:在所有环境中将 G1 设为默认垃圾收集器
G1 在 Java 9 中被设为默认垃圾收集器。当时,测试表明,在只有 1 个 CPU(或更少)且堆内存小于 1792 MB 的环境中,Serial 垃圾收集器效率更高。因此,在这些情况下,JVM 默认使用 Serial。
此后,G1 得到了改进,测试表明,对于所有堆大小,G1 现在都与 Serial 相当。通过减少同步的改进(JEP 522),G1 现在即使在 CPU 数量减少的情况下也能达到与 Serial 相同的性能。最后,G1 的原生内存消耗也有所降低,达到与 Serial 相当的水平。
顺理成章地,由于 G1 在所有标准上都等于或优于 Serial,即使在 CPU 较少和/或内存较小的环境中也是如此,因此它现在在所有环境中都是默认选择。
更多信息请参见 JEP 523。
JEP 527:TLS 1.3 的后量子混合密钥交换
通过为 TLS 1.3 实现混合密钥交换算法,增强需要安全网络通信的 Java 应用的安全性。这些算法将抗量子算法与传统算法结合,有助于抵御未来的量子计算攻击。
混合密钥交换算法将抗量子算法与传统算法结合,只要两种算法中有一个未被攻破,它就仍然安全。这种方法有助于防范量子攻击,同时也承认这些新算法尚未经历传统算法多年来所获得的测试和分析。
JDK 的 TLS 1.3 实现将支持三种新的后量子混合密钥交换方案,这些方案将基于模格的密钥封装机制(ML-KEM——通过 JEP 496 添加)与传统临时椭圆曲线 Diffie-Hellman(ECDHE)算法结合:
- X25519MLKEM768:将 ECDHE 与 X25519 和 ML-KEM-768 结合的混合方案,
- SecP256r1MLKEM768:将使用 secp256r1 曲线的 ECDHE 与 ML-KEM-768 结合的混合方案,
- SecP384r1MLKEM1024:将使用 secp384r1 曲线的 ECDHE 与 ML-KEM-1024 结合的混合方案。
更多信息请参见 JEP 527。
JEP 534:默认启用紧凑对象头
紧凑对象头使 JVM 能够以 64 位而不是 128 位存储对象头:22 位用于类指针,31 位用于哈希码,4 位预留给 Valhalla,其余位与之前一样用于 GC 年龄和 JVM 标志。
紧凑对象头通过 JEP 450 在 Java 24 中作为替代对象头结构以预览形式引入,随后在 Java 25 中退出预览。
此后,紧凑对象头已经证明了其稳定性和性能。
Oracle 使用 JDK 的完整测试套件对其进行了测试。Amazon 和 SAP 也对其进行了测试,并已默认启用。
多项实验表明,启用紧凑对象头可以提升性能:
- SPECjbb2015 基准测试使用的堆空间减少 22%,CPU 时间减少 8%。
- 无论是使用 G1 收集器还是并行收集器,SPECjbb2015 执行的垃圾收集次数都减少了 15%。
- 一个高度并行的 JSON 解析器基准测试运行速度快了 10%。
在 Java 27 中,紧凑对象头默认启用。旧布局预计将在未来版本中弃用。
更多信息请参见 JEP 534。
JEP 536:JFR 进程内数据脱敏
JFR 记录文件包含命令行参数以及环境变量值和系统属性,这些内容显示了进程是如何启动和配置的。因此,这些事件可能包含敏感数据,例如命令行参数、环境变量和系统属性中的机密信息。目前,这些数据会原样出现在记录文件中,这在共享记录时会带来敏感信息泄露的风险。
现在,JFR 默认会对多种类型的敏感信息进行掩码处理,无需任何额外配置。
你可以使用现有命令行选项 -XX:FlightRecorderOptions 的新子选项,显式选择 JFR 应掩码的信息。每个子选项指定一个或多个过滤器,用于选择要掩码的命令行参数、环境变量和系统属性。
redact-argument 子选项指定命令行参数的过滤器列表,redact-key 子选项指定针对环境变量和系统属性形式的键值对的过滤器列表。
过滤器使用 glob 模式,其中 * 和 ? 是通配符。如果某个过滤器匹配某个参数或键,则该参数或键值会在事件中记录为 [REDACTED]。多个过滤器之间用分号分隔,并按指定顺序求值。-XX:FlightRecorderOptions 的不同子选项之间用逗号分隔。
例如,要掩码任何名为“confidential”或“CONFIDENTIAL”的环境变量或系统属性,以及任何类似包含用户名和密码的 URL(即 username:password@host)的命令行参数,请使用:
要验证敏感信息是否已被正确掩码,请使用 jfr print 命令:
从预览中毕业的功能
以下从预览(或孵化器模块)毕业的功能现已成为标准功能:
没有!
这非常罕见,值得特别强调。一些长期处于预览状态的功能因等待 Valhalla 项目而受阻。
仍处于预览的功能
以下功能仍处于预览状态(或仍在孵化器模块中):
- JEP 531 - 惰性常量:第三次预览,这是一种用于创建按需初始化常量的新 API。有两处变化:移除了低级方法
isInitialized和orElse,新增了工厂方法Set.ofLazy(...)。 - JEP 532 - 模式匹配、
instanceof和switch中的基本类型:第五次预览,增加了对instanceof和switch中基本类型的支持,并增强了模式匹配以支持基本类型模式:在instanceof中、在switch分支中,以及在记录解构中。无变化。 - JEP 533 - 结构化并发:第七次预览,这是一种新 API,通过允许将多个并发任务视为单个工作单元,简化多线程代码的编写。
Joiner接口有多处变化:join()方法接受第三个参数,用于指定StructuredTaskScope可以抛出的异常;awaitAll()已被移除,改用allSuccessfulOrThrow()、anySuccessfulOrThrow()和awaitAllSuccessfulOrThrow(),这些方法会创建在发生异常时抛出ExecutionException的 Joiner;onTimeout()已由timeout()替代。 - JEP 537 - Vector API:第十二次孵化,这是一种用于表达向量计算的 API,会在运行时编译为受支持 CPU 架构的向量指令。无变化。JEP 中已明确表示,Vector API 将一直处于孵化状态,直到 Valhalla 项目的功能进入预览。这在预期之内,因为届时 Vector API 将能够利用 Valhalla 项目有望带来的性能和内存表示改进。
- JEP 538 - 密码学对象的 PEM 编码:第三次预览,这是一个为 Java 增加对隐私增强邮件(PEM)格式支持的新 API。为
PEM类新增了接受 BASE64 编码字节数组作为输入的构造方法;DEREncodable已重命名为BinaryEncodable;新增了EncryptedPrivateKeyInfo.getKeyPair()方法,并新增了用于表示密码学异常的CryptoException异常。
有关这些内容的详细信息,请参阅我之前的文章。
其他变更
JDK 中的各种新增内容:
Math.acosh(double)和StrictMath.acosh(double):返回一个double值的反双曲余弦。Math.asinh(double)和StrictMath.asinh(double):返回一个double值的反双曲正弦。Math.atanh(double)和StrictMath.atanh(double):返回一个double值的反双曲正切。String.encodedLength(Charset):返回此字符串使用指定字符集编码后的长度(以字节为单位)。BigDecimal.rootn(int, MathContext):返回此值的 n 次方根的近似值,并根据上下文设置进行舍入。DateTimeFormatter现在支持短时区偏移(+01而不是+01:00),参见 JDK-8210336。
JDK 27 中的所有新 API 可在 The Java Version Almanac - New APIs in Java 27 中找到。
内部变化、性能和安全
与所有 Java 新版本一样,OpenJDK 27 包含许多性能优化和安全增强。
在性能方面,我注意到几项有趣的改进:
HashMap.putAll()现在当Map是HashMap时有一条快速路径,会直接调用putHashMapEntries(),带来 66%–86% 的提升(PR #28243);- 为二分查找新增了 AVX2 架构的内建函数,对于超过特定阈值的数组(
int=256、long=768、short=512、char=512),带来 1.5 倍到 2.35 倍的提升(PR #30612); - 打开文件时消除系统调用:在 Unix 上,
FileOutputStream和RandomAccessFile过去在以写入方式打开文件后会调用fstat来拒绝目录。由于相关的打开操作已经会以EISDIR失败,因此额外的系统调用是多余的; - 密码学加速:为 AES/ECB、AVX2 上的 SHA-3、RISC-V 上的 AES/CTR 新增内建函数。
你可以在 Per-Ake Minborg 和 Claes Redestad 的这篇文章中找到一些有趣的性能改进:JDK 27 中的性能改进。
在安全方面,可以提到:
- 新增 TLS 证书压缩支持(JDK-8372526);
- 将 WISeKey 证书添加到 JVM 信任库(JDK-8372351);
- 新增命令
jcmd VM.security_properties,用于列出已启用的安全属性(JDK-8364182); - HSS/LMS 签名算法现在支持 RFC 9858 中定义的额外参数集。该 RFC 为 LMS/HSS 引入了使用 SHA-256/192 和基于 SHAKE 的哈希函数(SHAKE256/256 和 SHAKE256/192)的新参数集。这些新参数集允许使用更短的签名。
你可以在 Sean Mullan 的文章 JDK 27 安全增强中找到所有与安全相关的变更。
JVM 的一体化管理命令 jcmd 现在支持 Bash 补全(JDK-8357439)。
实验性的 JVM 编译器接口(JVMCI)功能已被移除(JDK-8382582)。引用发行说明:JVMCI 曾提供一种实验性的内部 Java API,用于用 Java 编写可由 HotSpot 调用的 JIT 编译器。经过十多年的实验,它在 JDK 内维护和测试的成本已经超过了它为所涉及的有限下游用例带来的收益。依赖 JVMCI 的下游项目现在必须在其自己的开发树中集成和维护它,或者继续使用较早的 JDK 版本。 GraalVM 是这些项目中最著名的一个;Graal 编译器已在其文档中不再提及 JVMCI,使用 Graal 编译器替代 C2 的做法应不再受支持。
JFR 事件
以下是 JVM 中新增的 Java Flight Recorder(JFR)事件:
ShenandoahPromotionInformation:无描述。
你可以在 JFR Events 页面中找到此 Java 版本支持的所有 JFR 事件。## 结论
Java 27 是一个小版本,没有重大变更或新功能。好消息是,它的继任者 Java 28 很可能会包含 Valhalla 项目的第一阶段,因为 JEP 401 - 值对象 已经有开放的 PR(#31122)!
要查看 Java 27 的所有变更,请查阅发行说明。
[LOADING...]
作者
Loic Mathieu
Kestra.io 首席软件工程师 | GCP GDE | Quarkus 贡献者 | 图书作者