JDK27正式发布,人麻了!

312 阅读13分钟

前言

2026年9月15日,Oracle正式发布了JDK 27,对应JSR 402,是Java SE 27的参考实现。

说实话,每次Java发布新版本,我都会习惯性看一眼JEP列表,然后判断“这个版本值不值得升级”。

很多版本是“预览版加预览版”,真正能落到生产环境的东西不多。

但JDK 27不太一样。

它包含9项足以单独成为JEP的增强,其中4项是预览功能、1项是孵化器功能。

更重要的是,其中有几项是默认行为变更——也就是说,你什么都不做,升级JDK就能受益。

今天这篇文章,我就把JDK 27的核心变化从头到尾给你拆解一遍。

希望对你会有所帮助。

更多项目实战在Java突击队网:susan.net.cn/project

一、JDK 27到底变了什么?

在深入每个特性之前,我先用一张表帮你建立整体认知。

JEP编号特性名称类型核心影响
JEP 523G1成为所有环境的默认GC正式启动更快,延迟更低
JEP 534紧凑对象头成为默认正式对象头从96位降到64位
JEP 527TLS 1.3后量子混合密钥交换正式默认启用,无需改代码
JEP 531惰性常量(第三预览)预览AI/数据应用的性能优化
JEP 532原始类型模式匹配(第五预览)预览switch/instanceof支持int/long等
JEP 533结构化并发(第七预览)预览并发编程更简单、更可靠
JEP 537Vector API(第十二孵化)孵化AI推理/科学计算向量加速
JEP 536JFR进程内数据脱敏正式敏感信息自动脱敏
JEP 538PEM编码API(第三预览)预览密钥/证书编解码标准化

这9项JEP,我按“对普通开发者影响程度”从高到低排列,逐一拆解。

二、G1成为所有环境的默认GC

这是最大的变化。

有些小伙伴在工作中可能遇到过这样的场景:写了个小工具、跑了个批处理脚本,启动的时候发现用的是Serial GC——单线程回收,启动快但一旦数据量上来就卡得不行。你以为是代码问题,其实是GC选错了。

从JDK 9开始,G1就已经是服务器环境的默认GC。

但如果你在一个内存受限的环境里跑Java——比如小容器、嵌入式设备、或者一个简单的命令行工具——JVM会默认选择Serial GC

Serial GC的问题很明显:单线程,Full GC时会长时间停顿

在小内存场景下,你可能感觉不到;但一旦数据量稍微大一点,停顿时间就会变得不可接受。

JDK 27的JEP 523把这件事改了:G1成为所有环境的默认GC,不再区分服务器和受限环境

2.1 为什么敢这么做?

Oracle在JEP里给出了明确的理由:经过这些年的持续优化,G1在所有指标上都已经和Serial持平了

具体来说:

吞吐量:JDK 27中减少了G1的同步开销(JEP 522),G1的最大吞吐量已经接近Serial。

延迟:G1在老年代回收时走的是增量回收,而不是Serial那种全量回收,所以最大延迟一直比Serial好。

原生内存:最近几个版本把G1的原生内存占用降到了和Serial相当的水平。

启动时间:在小堆场景下,G1的启动开销已经优化到不再明显。

2.2 对你意味着什么?

什么都不用改

你升级到JDK 27,不指定GC参数,JVM自动用G1。

如果你之前在小内存环境里被Serial GC的Full GC停顿折磨过,升级JDK 27后这个问题会自动消失。

当然,如果你需要极致启动速度,仍然可以显式指定Serial:-XX:+UseSerialGC

但默认情况下,G1已经是更好的选择。

三、紧凑对象头成为默认

对象头从96位砍到64位。

这是另一个默认行为变更,而且是“悄悄生效”的那种。

3.1 对象头里到底存了什么?

Java对象在堆里是怎么存的?

每个对象都有一个“对象头”,里面至少包含Mark WordKlass Pointer两部分。

在64位JVM上,传统布局是:

  • Mark Word:64位(哈希码、GC年龄、锁状态等)
  • Klass Pointer:64位(指向类元数据)

对象头总共96位,也就是12字节

加上对象体,一个最简单的new Object(),在64位JVM上实际占用16字节(对象头12字节 + 对齐填充4字节)。

3.2 紧凑对象头怎么做的?

JEP 534把Klass Pointer从64位压缩到了32位,对象头总共变成64位,即8字节

为什么能压缩?

因为JVM的类元数据空间(Metaspace)通常不会超过4GB(32位地址空间足够寻址)。

Klass Pointer其实只需要存一个索引,不需要完整的64位地址。

效果new Object()从16字节降到12字节(8字节对象头 + 4字节对齐填充)。堆占用直接减少25%

3.3 为什么这很重要?

堆占用减少25%,意味着:

  • 同样的内存能装更多对象
  • GC压力更小(对象少了,扫描和回收的负担就小了)
  • 数据局部性更好(对象更紧凑,CPU缓存命中率更高)

对于大规模Java应用——特别是那些创建大量小对象的场景——这是一个实打实的性能提升

紧凑对象头从JDK 24开始就是可选功能,经过两个版本的验证,JDK 27正式把它设为默认。

和G1一样,你不需要做任何事,升级就生效

四、TLS 1.3后量子混合密钥交换

为“量子时代”提前上锁。

“量子计算离我还远着呢,跟我有什么关系?”

这个问题我被问过不止一次。我的回答是:等量子计算能破解RSA的那一天,你今天的加密数据可能已经被存了好几年了。

攻击者的策略叫“先存后破”——现在把加密流量存下来,等量子计算机成熟了再解密。所以后量子加密不是“未来的事”,是“现在就要做的事”。

4.1 JEP 527做了什么?

JDK 27为TLS 1.3引入了后量子混合密钥交换算法

所谓“混合”,就是把抗量子算法传统算法结合起来——即使量子计算破解了传统算法那一半,抗量子算法那一半仍然安全。

新增的算法包括:

  • X25519MLKEM768(默认组列表中优先级最高)
  • SecP256r1MLKEM768
  • SecP384r1MLKEM1024

4.2 关键点:默认启用,无需改代码

如果你用的是javax.net.ssl API,升级JDK 27后,这些算法默认就会生效,不需要修改任何代码。

这意味着:你现有的HTTPS通信,在升级JDK 27后,自动获得了后量子加密保护

五、惰性常量

它是AI和数据应用的性能利器。

惰性常量(Lazy Constants)是第三次预览了,但这个特性的价值值得反复说。

5.1 它解决什么问题?

Java里传统的static final常量在类加载时就必须初始化。

如果你的常量需要昂贵的计算——比如从数据库加载配置、解析一个大文件、初始化一个ML模型——那类加载就会变得很慢。

惰性常量允许你延迟初始化,而且JVM会把它当成真正的常量来优化——性能等价于final字段。

5.2 代码示例

// 传统的static final——类加载时就得算
public static final List<Config> CONFIGS = loadFromDatabase();

// 惰性常量——用到的时候才算
private static final LazyConstant<List<Config>> CONFIGS = 
    LazyConstant.of(() -> loadFromDatabase());

// 第一次调用时初始化,之后直接走缓存
public List<Config> getConfigs() {
    return CONFIGS.get();
}

为什么这跟AI有关?

因为AI应用里大量存在这种场景——模型权重、tokenizer词表、向量索引,都是初始化昂贵但后续只读的数据。

惰性常量让这些数据可以按需加载,同时不牺牲运行时的性能。

六、原始类型模式匹配

switch终于支持int了。

这是第五次预览,但每预览一次,就离正式版更近一步。

6.1 解决了什么痛点?

以前的switch只能匹配引用类型(String、enum、包装类)。

你要匹配int,只能用传统的switch-case,没法用模式匹配的威力。

JEP 532允许原始类型用于模式匹配、instanceofswitch

6.2 代码对比

// 以前:int匹配只能这样写
switch (statusCode) {
    case 200:
        return "OK";
    case 404:
        return "Not Found";
    default:
        return "Unknown";
}

// JDK 27预览:可以用模式匹配了
Object obj = getStatusCode();
return switch (obj) {
    case int i when i == 200 -> "OK";
    case int i when i == 404 -> "Not Found";
    case String s -> "String: " + s;
    default -> "Unknown";
};

同时,这个JEP还加强了switch的支配性检查,让编译器能在编译期发现更多错误。

七、结构化并发

结构化并发第七次预览了。

虽然还是预览,但它的思路值得每个Java开发者关注。

7.1 传统并发的问题

// 传统写法:两个任务并发,但错误处理一团糟
Future<User> userFuture = executor.submit(() -> fetchUser(id));
Future<Order> orderFuture = executor.submit(() -> fetchOrder(id));

try {
    User user = userFuture.get();
    Order order = orderFuture.get();
    return new Result(user, order);
} catch (Exception e) {
    // 一个失败了,另一个还在跑,怎么取消?
    // 线程泄漏怎么办?
    throw e;
}

问题在于:这两个任务的生命周期没有和父任务绑定

父任务失败了,子任务可能还在跑;子任务失败了,父任务不知道该怎么取消另一个。

7.2 结构化并发的写法

try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Supplier<User> user = scope.fork(() -> fetchUser(id));
    Supplier<Order> order = scope.fork(() -> fetchOrder(id));
    
    scope.join();           // 等待所有子任务
    scope.throwIfFailed();  // 任一失败则抛出
    
    return new Result(user.get(), order.get());
}
// 离开try块时,scope自动关闭,所有未完成的子任务自动取消

核心价值:子任务的生命周期严格嵌套在父任务内。父任务失败,子任务全部取消;子任务失败,父任务感知并处理。没有线程泄漏,没有孤儿任务。

八、Vector API

它是AI推理的加速器。

Vector API第十二次孵化了。

虽然还在孵化阶段,但它在AI推理和科学计算领域的价值已经非常明确。

Vector API允许开发者在支持的CPU上利用SIMD指令——一条指令同时处理多个数据。

对于矩阵运算、向量相似度计算这类AI推理中高频出现的操作,性能提升可以是数量级的

// 向量加法——一次处理多个float
FloatVector a = FloatVector.fromArray(SPECIES, arr1, i);
FloatVector b = FloatVector.fromArray(SPECIES, arr2, i);
FloatVector c = a.add(b);
c.intoArray(result, i);

如果你的AI应用跑在支持AVX-512或ARM SVE的CPU上,Vector API能把这些硬件的向量计算能力直接暴露给Java代码

九、其他值得关注的改进

除了9项JEP,JDK 27还有几十项非JEP改进:

JEP 536:JFR进程内数据脱敏——JDK Flight Recorder在记录离开进程前,对命令行参数、环境变量和系统属性进行脱敏。生产环境做性能分析时,不会再意外泄露密钥。

ML-KEM/ML-DSA私钥编码更新——后量子密码算法的密钥编码标准化,X25519和Ed25519性能提升。

JSON线程转储——线程转储中的线程标识、线程数和进程标识改为JSON数字,监控工具解析更方便。

jcmd VM.security_properties——新增命令,可在运行时查看活动的安全属性。

移除JVMCI——部分旧选项和功能被移除。

十、优缺点

优点

1. G1全场景默认,小内存环境不再受Serial GC折磨
吞吐量、延迟、内存占用、启动时间全面持平甚至优于Serial,默认用G1是更安全的选择。

2. 对象头砍到64位,堆占用降低25%
同样的内存能装更多对象,GC压力更小,数据局部性更好。大规模应用直接受益

3. 后量子加密默认启用,无需改代码
javax.net.ssl的应用自动获得抗量子攻击能力。这是安全层面的基础性升级

4. 惰性常量为AI/数据应用优化
模型权重、向量索引等昂贵初始化数据可以按需加载,运行时性能等价于final

5. 结构化并发让并发编程更可靠
子任务生命周期严格嵌套,没有线程泄漏,没有孤儿任务。

6. JFR数据脱敏,生产环境更安全
性能分析时不会意外泄露密钥和环境变量。

注意事项

1. 非LTS版本,生产环境需谨慎
JDK 27不是LTS,Oracle更新到2027年3月。生产环境建议用JDK 25 LTS。

2. 预览/孵化特性需要--enable-preview
惰性常量、原始类型模式匹配、结构化并发、Vector API都需要显式启用预览标志,且可能与未来版本不兼容。

3. JVMCI被移除
如果你用了Graal JIT编译器(基于JVMCI),需要确认兼容性。

4. 紧凑对象头可能影响某些诊断工具
依赖对象头布局的工具(如某些Profiler)可能需要更新。

十一、适用场景

场景推荐程度理由
尝鲜/学习/个人项目✅✅✅ 强烈推荐默认变更直接体验,预览特性可以提前探索
小内存容器/嵌入式✅✅✅ 强烈推荐G1默认+紧凑对象头,启动和内存都受益
大规模Java应用✅✅ 推荐堆占用降低25%,但需评估非LTS风险
安全敏感应用(HTTPS)✅✅✅ 强烈推荐后量子加密默认启用,零代码改动
AI/数据密集型应用✅✅ 推荐惰性常量+Vector API,但预览特性需评估
需要长期稳定支持的生产环境⚠️ 需评估JDK 25 LTS更稳妥
依赖Graal JIT的项目❌ 不推荐JVMCI被移除,需等待GraalVM跟进

更多项目实战在Java突击队网:susan.net.cn/project

十二、写在最后

回到最初的问题:JDK 27值不值得升级?

我的判断是:值得尝鲜,但生产环境等JDK 28或JDK 29 LTS更稳妥。

JDK 27最大的价值不在于某个“炫酷的新语法”,而在于三个默认行为变更

G1成为全场景默认——你什么都不做,启动更快、延迟更低。

对象头砍到64位——你什么都不做,堆占用降25%。

后量子加密默认启用——你什么都不做,HTTPS通信就获得了抗量子保护。

这三件事加起来,是实打实的运行时收益,不是“预览版的预览版”。

预览特性里,结构化并发惰性常量是最值得关注的。

结构化并发如果转正,会改变Java并发编程的写法;惰性常量如果转正,会成为AI应用的标配。

JDK 27不是LTS,如果你现在的生产环境跑在JDK 21或JDK 25 LTS上,不用急着升

但如果你在开发新项目、跑实验环境、或者想提前感受Java的演进方向——JDK 27值得下载跑一跑