Java 27 上线:统一 G1 默认值,并把后量子能力带入 TLS 1.3

2026-09-16 28 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Java 27 已于 9 月 15 日正式 GA。作为 2026 年第二个功能版本,它包含 9 个 JEP,其中两项变化尤其值得平台团队关注:JEP 523 将 G1 统一为所有环境下的默认垃圾回收器,TLS 1.3 则开始引入后量子加密能力。

这两个变化都发生在基础设施层。业务代码可能一行不改,但应用的停顿特征、CPU 消耗、TLS 握手以及跨系统兼容性仍可能发生变化。因此,升级前不能只确认“能否启动”,还要重新验证运行时基线。

G1 默认值统一,解决的是环境漂移

过去,同一份 JAR 在不同机器、容器镜像或硬件条件下,可能因为 JVM 对默认垃圾回收器的选择不同而表现出不同的延迟和吞吐特征。Java 27 通过 JEP 523 将 G1 设为所有环境的默认 GC,减少了这种由隐式默认值造成的差异。

这项调整的直接收益不是“所有应用突然更快”,而是行为更容易预测:

  • 开发、测试和生产环境更容易使用同一种默认 GC;
  • 容器迁移或节点规格变化时,不容易意外切换回收器;
  • 没有显式配置 GC 的服务,也能获得一致的运行时起点;
  • 性能问题排查时,团队少了一个隐含变量。

但默认值仍然不等于最优值。大堆、极低延迟服务、批处理任务和短生命周期命令行程序的目标不同。已经显式使用其他回收器的应用,不应仅因为默认值变化就删除现有参数。

先确认 JVM 实际选择了什么

升级后的第一步,可以直接查看启动日志,而不是根据机器类型猜测:

export JAVA_HOME=/opt/jdk-27
export PATH="$JAVA_HOME/bin:$PATH"

java -version
java -Xlog:gc=info -version

在 Java 27 的默认配置下,GC 日志应显示 JVM 正在使用 G1。生产环境建议保留显式参数,使部署意图不会随着基础镜像或 JDK 版本变化:

java \
  -XX:+UseG1GC \
  -Xms1g \
  -Xmx1g \
  -Xlog:gc*,safepoint:file=logs/gc.log:time,uptime,level,tags \
  -jar app.jar

显式写出 -XX:+UseG1GC 并非技术上的必需条件,但对需要可复现配置的生产系统很有价值。

用一个小程序建立 Java 27 的 GC 基线

下面的示例会持续制造短期对象,并保留少量数据,以便观察 G1 的回收活动。它只是验证日志和运行时行为的探针,不是正式基准测试。

cat > MemoryProbe.java <<'EOF'
import java.util.ArrayList;
import java.util.List;

public class MemoryProbe {
    public static void main(String[] args) throws Exception {
        List<byte[]> retained = new ArrayList<>();

        for (int i = 0; i < 2_000; i++) {
            byte[] block = new byte[512 * 1024];
            block[0] = 1;

            if (i % 40 == 0) {
                retained.add(block);
            }

            if (i % 200 == 0) {
                System.out.printf("iteration=%d, retained=%d MB%n",
                        i, retained.size() / 2);
                Thread.sleep(20);
            }
        }

        System.out.println("done, retained blocks=" + retained.size());
    }
}
EOF

javac MemoryProbe.java
java \
  -Xms256m \
  -Xmx256m \
  -XX:+UseG1GC \
  -Xlog:gc*,safepoint:file=gc.log:time,uptime,level,tags \
  MemoryProbe

grep -E "Using|Pause|Concurrent" gc.log | head -n 30

在真实服务中,建议对升级前后的相同流量窗口比较以下指标:

  • GC 暂停的 p50、p95 和 p99;
  • 请求延迟的 p95 和 p99;
  • GC 前后的堆占用;
  • CPU 使用率和分配速率;
  • Full GC 次数;
  • 容器是否接近内存限制,或出现 OOM Kill。

不要只比较平均暂停时间。一次罕见但很长的暂停,往往比平均值更能解释生产环境的超时。

后量子能力进入 TLS 1.3,不代表连接自动完成升级

Java 27 将后量子加密能力带入 TLS 1.3,是面向未来网络安全的重要变化。不过,从运维角度看,真正需要验证的是协商结果和互操作性。

一次 TLS 连接是否实际采用相应能力,还取决于对端服务器、JDK 安全提供者、配置策略和中间网络设备。仅升级客户端 JDK,并不能证明每条 TLS 1.3 连接都已经获得后量子保护。具体算法名称、启用方式和限制,应以 Java 27 的安全提供者文档及部署环境策略为准。

下面可以用一个最小 Java 客户端确认 TLS 1.3 连接,并打印协商出的协议与密码套件。把示例地址替换成自己的测试端点:

cat > TlsProbe.java <<'EOF'
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import javax.net.ssl.SSLContext;

public class TlsProbe {
    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.err.println("Usage: java TlsProbe https://host/path");
            System.exit(2);
        }

        SSLContext tls13 = SSLContext.getInstance("TLSv1.3");
        tls13.init(null, null, null);

        HttpClient client = HttpClient.newBuilder()
                .sslContext(tls13)
                .build();

        HttpRequest request = HttpRequest.newBuilder(URI.create(args[0]))
                .GET()
                .build();

        HttpResponse<Void> response = client.send(
                request, HttpResponse.BodyHandlers.discarding());

        System.out.println("HTTP status: " + response.statusCode());
        response.sslSession().ifPresent(session -> {
            System.out.println("Protocol: " + session.getProtocol());
            System.out.println("Cipher suite: " + session.getCipherSuite());
        });
    }
}
EOF

javac TlsProbe.java
java TlsProbe https://example.com/

如果需要检查更完整的握手过程,可在隔离的测试环境中启用 JSSE 调试日志:

java \
  -Djavax.net.debug=ssl,handshake \
  TlsProbe https://your-test-endpoint.example/

调试输出可能包含证书、主机名和连接细节,不宜在生产环境长期打开,也不要未经处理就上传到公共工单或日志平台。

TLS 升级还应覆盖这些场景:

  • Java 客户端连接旧版网关或负载均衡器;
  • Java 服务端面对不同 JDK、浏览器和移动端客户端;
  • TLS 终止位于反向代理,而不是 Java 进程内部;
  • 企业代理、安全设备或服务网格会检查并重新建立 TLS;
  • 内部服务使用私有 CA 或定制安全提供者。

升级时把默认值变成显式决策

Java 27 的变化降低了默认环境之间的差异,但上线仍应采用分阶段策略:

  1. 固定 JDK 发行版、构建号和容器镜像摘要,避免测试与生产使用不同构建。
  2. 记录当前 GC、堆参数、TLS 参数和安全提供者,建立升级前基线。
  3. 在预生产环境回放代表性流量,同时采集 GC、延迟、CPU 和内存数据。
  4. 对关键上下游执行 TLS 1.3 互操作测试,不要只测试一个公开网站。
  5. 先灰度无状态实例,再扩大范围,并准备可快速回退的旧镜像。
  6. 保留显式 GC 参数和必要的 TLS 策略,避免再次依赖隐含默认值。

G1 成为统一默认值,让 Java 27 的运行时行为更一致;后量子能力进入 TLS 1.3,则让平台开始面对下一阶段的密码迁移。前者需要性能测量,后者需要端到端协商验证。两者都不能只靠版本号完成验收。


相关推荐