比 Python 快 13 倍,比 C 慢 17%,Java 被骂慢骂了 20 年,原来是 Spring 的锅。
"Java 太慢了",类似这样的话,我听了快 10 年了。十年了我成长了,但有些人还在"刻舟求剑"。
今天,我在一个大佬的微信群里,看到又有人在讨论这个。说慢,又拿不出具体的数据,纯靠偏见在讨论。
上一次讨论类似问题,还是在月初。刚好有老外网友做了一个实验,对 62 门编程语言速度做了一个比较,通过莱布尼茨公式**计算 π 值,然后给出运行速度的排名,最慢是 Python (CPython)。实验过程和结果都公开透明,参见网址:https://github.com/niklas-heer/speed-comparison。
有时候,我挺理解那些对 Java 有偏见的程序员的。比如,Python 程序员优雅地写下一行代码解决问题时,Java 还在吭哧吭哧地定义类和接口,当 js 在浏览器中快速执行时,Java 的应用可能还需要加载 Spring 上下文...
但这也不能说明 Java 就是慢。所以,今天,我想稍微花点时间,尝试为这些"偏见"找到源头,并用数据和原理告诉你:Java 不慢,慢的很可能是你的认知还停留在 20 年前。
这些偏见,我都经历过
偏见 1 解释执行,肯定慢
这是最经典的误解。确实,Java 编译成字节码,再由 JVM 解释执行,中间多了一层。但你知道吗?现代 JVM 90% 的代码根本不走解释执行!
甚至是在某些情况下,经过 JVM 充分的优化,Java 程序能比 C++ 程序更快。特别是在一些依赖 JVM 运行时分析和自适应优化的场景下。通过 JVM 的"即时编译"(JIT)和自适应优化能力,能在运行时做出静态编译语言难以实现的动态决策。
偏见 2 GC STW 卡顿慢
Stop-The-World(STW)是 Java 程序员永远的痛。但这次我要说:你可能从来没用过真正的低延迟 GC。
确实是没有任何一个商业化的 Java GC 能实现完全的零 STW,但目前主流的现代 GC,其设计核心都在于将 STW 时间缩短到极致,有些甚至能达到亚毫秒级别。
在某些分代的 JVM 中,其部分分代的 GC 并不需要 STW,也或者说是大部分 GC 阶段不需要 STW。并且,JVM 还推出了众多的优化手段,包括:多线程并行,并发标记/清理,全阶段并发 + 读屏障,着色指针和读屏障等。
偏见 3 启动慢,性能差
确实,一些企业级框架太过于笨重。尤其是,Spring + MyBatis + Dubbo,一套组合拳下来,启动 3 分钟,内存 2GB 起步。这印象太深了,以至于很多人把框架的臃肿等同于语言的低效。
反射、AOP、bean 的顺序加载、连接池初始化等,它能不慢吗?但,这个慢,是框架造成的,并不是 Java 慢。
数据不会说谎
让我们来看一个文章开头所说的真实的基准测试。GitHub 项目 speed-comparisonhttps://niklas-heer.github.io/speed-comparison/使用莱布尼茨公式计算 π 值,在10 亿次迭代下,各语言表现如下。
| 语言 | 中位执行时间 | 与最快速度比值 |
|---|---|---|
| C | 7.08s | 1.0x |
| Rust | 7.11s | 1.0x |
| Java (GraalVM) | 7.33s | 1.04x |
| C++ | 8.16s | 1.15x |
| Java (OpenJDK) | 8.26s | 1.17x |
| Go | 10.4s | 1.47x |
| Node.js | 31.2s | 4.41x |
| Python | 113.17s | 15.99x |
Java 只比 C 慢 17%,但比 Python 快 13 倍!这个结果惊不惊讶?意不意外?
更扎心的是,在这个 CPU 密集型计算场景中,Python 甚至比 Node.js 还慢 3.6 倍。那些说Python 开发快就够了的人,可能没经历过计算密集型任务的绝望。
即使是 OpenJDK,也比 Go、PHP 等常见语言快。Github 上还有很多其它案例,我就不细说了,大家自己去看看吧。
为什么一些人会觉得 Java 慢?
根据我收集的资料和第一手经验,我觉得偏见主要来自以下几个层面。
排在第一个的是 Java 的历史债务。不少人印象里的 Java,是 JDK 1.4 的 Java,那个时候的 Java 确实慢。
- 早期 JVM:纯解释执行,JIT 编译器形同虚设
- 老旧的 GC:Serial GC 和 Parallel GC 动不动就 Full GC,停顿几秒
- Applet** 噩梦:浏览器里那个卡顿的小程序,是整个 Java 生态的原罪
但现在是 2025 年!JDK 21、JDK 25 都出来了,ZGC 的停顿时间小于 1 毫秒,GraalVM 的 AOT 编译让启动速度快如闪电。他们的经验,也该更新了。
排在第二的应该是 JVM 中的技术迷雾,JVM 的"黑魔法"让你测不准。甚至是,只有 Java 面试才有调优,其它语言可能都没这么卷。
现代 JVM 太复杂了,复杂到连资深工程师都容易误判,看下面 3 个陷阱。
第一个陷阱就是 JIT** 的预热。
csharp
// 你写的代码
public void calculate() { /* 复杂计算 */ }
// 实际执行路径
// 前 1000 次:解释执行 → 慢!
// 1000-10000 次:C1 编译 → 稍快
// 10000+ 次:C2 编译 + 激进优化 → 峰值性能!
很多人在预热阶段就下了"Java 好慢"的结论,根本没测到 JIT 优化后的真实性能。
第二个陷阱是 JVM 逃逸分析。
typescript
public String process() {
// 你以为:堆分配,GC 压力大
StringBuilder sb = new StringBuilder();
// 实际上:JVM 分析发现 sb 不会逃逸,直接栈分配,0 GC!
return sb.toString();
}
JVM 的智能优化远超你的想象,但你用传统性能分析工具根本看不出来。
第三个陷阱是微基准测试骗局。
没有 JMH 的微基准测试都是耍流氓。JVM 会消除死代码、循环展开、内联虚方法等,你写的测试用例可能什么都没测到。。。
接下来是对 GC 的误解,源自于多数人根本不了解现代垃圾回收器。
- ZGC(JDK 15+):停顿时间 < 1ms,支持 16TB 堆内存
- Shenandoah:并发整理,吞吐量与低延迟兼得
- G1:JDK 9 后的默认 GC,可预测的停顿模型
但大部分开发者还在用 JDK 8 的 Parallel GC,然后抱怨"GC 卡顿"。这不是 Java 的问题,这是你不升级的问题。
然后是框架得背锅。慢的是 Spring,不是 Java。
我们来看一个真实案例。
java
// 纯 Java 计算斐波那契数列
public long fib(int n) { /* 递归实现 */ } // 耗时:0.5ms
// Spring Bean 版本
@Service
public class FibService {
@Cacheable
public long fib(int n) { /* 同样实现 */ } // 耗时:15ms
}
Spring 的代理、AOP、事务、缓存一层层叠加,性能损耗可达 30 倍。但开发者往往把这笔账算在 Java 头上,而不是框架设计上。
反射是最大的元凶,而且到处是反射。Spring 依赖注入、MyBatis 动态代理、JSON 序列化,哪里都有反射。反射调用比直接调用慢50-100 倍,且完全无法被 JIT 优化。
说白了,不是 Java 慢,是你用的框架在"犯罪"。
最后是部署形态,容器时代的"水土不服"。
在 Kubernetes 时代,Java 确实显得格格不入。
- 启动时间:JVM 加载 2000+ 核心类,Spring 扫描 500+ Bean,启动 30 秒起步
- 内存占用:JVM 本身占 200MB,堆内存再分配 1GB,镜像臃肿
- 资源感知:旧版 JVM 不认识 Docker 的 cgroup 限制,导致 OOM Kill
但这正是Quarkus、Micronaut、Spring Native等要解决的问题。通过 AOT 编译和 GraalVM 原生镜像,Java 应用的启动时间可缩短至0.05 秒,内存占用降至30MB。
Java 的真实性能定位
基于上述分析,Java 的真实性能画像应该是:
CPU 密集型,碾压 Python
CPU 密集型,接近 C++,碾压 Python。尤其是在科学计算、大数据处理(Hadoop/Spark)、高频交易(LMAX Disruptor)领域,Java 是事实标准。JIT 编译后的代码执行效率可达 C++ 的90% 以上。
内存管理,全自动,高吞吐
虽然 GC 有开销,但对比手动内存管理(C++)或引用计数(Python),Java 的吞吐量优势在 多线程环境 下尤为明显。ZGC 的出现更补齐了低延迟短板。
并发编程,生态最成熟
JUC(java.util.concurrent)、Fork/Join 框架、虚拟线程等让 Java 的并发模型远超 Python 的 GIL 限制和 Node.js 的单线程。
当然,Java 也有不少短板的。
比如,冷启动。
Serverless 场景下,Python/Node.js 的毫秒级启动仍有优势。但 GraalVM 原生镜像已基本解决此问题。
再比如,内存占用,仍偏高了些。
即使优化后,JVM 的内存足迹仍大于 Go 或 Rust,这在边缘计算场景确实是劣势。
总结
真相很可能和某些群体想象的不一样,偏见是源于认知滞后。
Java 的"慢"是一个技术神话,其根源是:
- 时间差:用 2004 年的 Java 对比 2024 年的 Python
- 对象错:把 Spring 的慢当作 Java 的慢
- 测量错:在 JIT 预热阶段下结论
- 信息差:不知道 ZGC、GraalVM、Quarkus 的存在
- 定位差:Java 要和所有的语言比,却忽略了它的跨平台以及成熟的社区
作为技术人员,我们确实应该持续学习,要知道 JDK 每 6 个月一个版本,性能优化日新月异。
最后,我想说的是:Java 不慢了,慢的是你的技术栈该升级了。还是那多篇历史文章中说到的话,做个结尾吧。