Java 性能优化

线上 CPU 打满,接口 RT 飙到 5 秒。你开始排查:业务代码没问题,数据库也正常,缓存也生效——但 GC 日志一打开,Young GC 每分钟 20 次,每次停顿 800ms。

这不是极端案例。JVM 性能问题有三个显著特点:难以复现(本地怎么测都正常,一上生产就出问题)、定位困难(表象是接口慢,但根因可能是 GC、可能是 JIT、可能是 I/O)、修复成本高(改错 JVM 参数可能让情况更糟)。

性能优化的本质,是在资源受限的条件下,找到真正的瓶颈并加以解决。很多人花大量时间优化代码细节,却忽视了更根本的问题——线程模型是否合理?GC 配置是否匹配业务特征?I/O 模型是否选对了?

本分类聚焦 Java 性能优化的核心技术体系,从 JVM 内存模型与 GC,到 Java 并发模型与同步机制,再到 JIT 编译原理与 AOT 优化,最后到 I/O 模型与性能剖析工具——帮你建立从「发现问题」到「定位根因」到「正确修复」的完整能力。

模块结构

本分类按主题分为 6 个子模块:

子模块核心问题典型场景
性能指标怎么衡量性能?哪些指标最关键?QPS/TPS 定义、延迟分位数、吞吐量计算
Java 并发模型线程怎么用?同步怎么做?异步怎么写?线程池配置、死锁排查、虚拟线程迁移
内存模型与 GC对象怎么分配?垃圾怎么回收?停顿怎么控制?Young GC 频繁、Full GC 过长、内存泄漏
JIT 编译与 AOT代码怎么被编译成机器码?哪些优化是 JIT 做的?方法内联、逃逸分析、GraalVM 原生镜像
I/O 模型同步 vs 异步、阻塞 vs 非阻塞的取舍?零拷贝怎么用?高并发网络编程、文件传输优化、Netty 调优
性能剖析怎么找到真正的性能瓶颈?工具怎么用?Arthas 诊断、JFR 分析、火焰图解读

性能问题的演进路径

理解性能问题,要从系统的演进阶段出发:

flowchart TD
    subgraph 阶段一["阶段一:功能正确"]
        A["代码跑通"]
        B["单元测试通过"]
    end

    subgraph 阶段二["阶段二:并发暴露"]
        C["多线程并发"]
        D["线程安全漏洞\n可见性/有序性/原子性"]
    end

    subgraph 阶段三["阶段三:GC 压力"]
        E["数据量增长"]
        F["GC 频繁/停顿过长\n内存泄漏"]
    end

    subgraph 阶段四["阶段四:I/O 瓶颈"]
        G["高并发请求"]
        H["网络/磁盘 I/O 成为瓶颈"]
    end

    subgraph 阶段五["阶段五:深度优化"]
        I["JIT 编译优化"]
        J["AOT 预编译\nGraalVM 原生镜像"]
    end

    A --> B --> C --> D --> E --> F --> G --> H --> I --> J

大多数工程师会在阶段二和阶段三遇到问题,但真正的高手会在设计阶段就避免这些问题的根源。

性能优化的核心原则

在动手优化之前,有几条铁律:

原则一:先测量,再优化。 不要猜测瓶颈在哪,用数据说话。一个常见误区是「我觉得这里会慢」,结果优化了半天,性能没提升,反而代码可读性下降了。

原则二:优化要站在 ROI 最高的点。 优化 1% 的代码不如优化占比 50% 的热点路径。先找到 p99 延迟最高的接口,再找到这个接口中最耗时的方法。

原则三:理解 trade-off 再做决策。 切换到 ZGC 降低了停顿时间,但吞吐量可能下降 5%。使用虚拟线程提升了并发能力,但 synchronized 的性能问题会放大。这些权衡必须在优化前就理解清楚。

原则四:不要优化不存在的问题。 如果系统 CPU 使用率只有 30%,吞吐量完全满足需求,GC 停顿在可接受范围内——不要动它。过度优化是另一种浪费。

Java 性能问题的分类

并发问题

并发问题是最常见也是最难排查的性能问题类别:

flowchart TD
    A["并发问题"] --> B["线程安全"]
    A --> C["死锁/活锁"]
    A --> D["锁竞争"]
    A --> E["上下文切换开销"]

    B --> B1["可见性问题\nvolatile"]
    B --> B2["原子性问题\nCAS/Atomic"]
    B --> B3["有序性问题\nhappens-before"]

    C --> C1["循环依赖"]
    C --> C2["锁顺序不一致"]

    D --> D1["锁粒度过粗"]
    D --> D2["热点竞争\nLongAdder"]

    E --> E1["线程数过多"]
    E --> E2["伪共享"]

典型症状

  • CPU 使用率不高,但接口 RT 高——可能是锁竞争或上下文切换过多
  • 线程 dump 显示大量线程处于 BLOCKED/WAITING 状态——锁竞争或死锁
  • CPU 使用率高,但吞吐量不高——可能是 GC 问题或 I/O 阻塞

GC 问题

GC 问题是 JVM 性能问题的重灾区:

问题类型典型症状可能原因解决方案
Young GC 频繁每分钟 20+ 次,停顿 500ms+对象分配速率过高减少短期对象创建、增大年轻代
Full GC 频繁老年代持续增长内存泄漏、大对象直接晋升排查泄漏、调整晋升阈值
GC 停顿过长p99 延迟高G1 混合回收时间过长切换 ZGC、调整 G1 参数
内存持续增长OOM集合未清理、类加载器泄漏堆转储分析、修复泄漏源

I/O 问题

I/O 问题在高并发场景下尤为突出:

典型症状

  • 线程池打满,大量请求等待 I/O——BIO 模型下每个连接一个线程的问题
  • 网络延迟高但 CPU 利用率低——可能是阻塞 I/O 导致的线程浪费
  • 文件传输性能差——没有利用零拷贝优化

核心矛盾:同步 I/O 简单但浪费资源,异步 I/O 高效但编程复杂。选择取决于业务特征。

各子模块导读

性能指标

如果你不确定怎么衡量性能,从这里开始。

核心概念性能指标总览——吞吐量和延迟的区别、黄金指标;延迟分析——p50/p90/p99 的含义、延迟分布;吞吐量——QPS/TPS 的定义与计算;SLO/SLI/SLA——如何设定性能目标。

工具与方法性能测试工具——JMeter、wrk、 Gatling;JMH 使用指南——微基准测试的正确姿势。

Java 并发模型

这是整个分类的核心模块,与日常开发关系最密切。

入门必读线程生命周期与状态转换——NEW/RUNNABLE/BLOCKED/WAITING/TIMED_WAITING/TERMINATED;Java 内存模型(JMM)——可见性、有序性、原子性的根源;happens-before 原则——8 大规则,理解并发 Bug 的基础。

同步机制synchronized 实现原理——锁升级过程;AQS 框架——ReentrantLock、Semaphore、CountDownLatch 的共同基础;ReentrantLock——比 synchronized 更灵活的锁;ReadWriteLock 与 StampedLock——读多写少场景的优化。

原子操作CAS 原理——无锁编程的核心;LongAdder——热点竞争的解决方案。

异步编程CompletableFuture——链式异步调用;Fork/Join 框架——分治并行计算;响应式编程——Reactor 与 WebFlux。

虚拟线程虚拟线程深度解析——Loom 架构与Continuation;虚拟线程 vs 平台线程——性能对比与选型;结构化并发——Java 21 的并发新范式;Scoped Values——线程局部变量的替代。

内存模型与 GC

如果你遇到 GC 问题,这里是必读的。

基础JVM 内存区域划分——堆/栈/元空间/直接内存;堆内存详解——Eden/Survivor/老年代;对象生命周期与内存分配——分配、晋升、回收。

原理可达性分析——GC Roots 的定义;引用类型——强/软/弱/虚引用的回收时机;标记-清除/复制/整理算法——三种基础算法;分代收集理论——为什么分代,分代如何工作。

收集器Serial/Parallel/CMS——历史收集器;G1 收集器——Java 9+ 默认;G1 Region 与 Remembered Set——G1 的核心数据结构;ZGC 深度解析——亚毫秒停顿的秘诀;ZGC 染色指针与读屏障——ZGC 的底层机制;Shenandoah——OpenJDK 的低延迟 GC;GC 对比矩阵——各收集器的选型建议。

实战GC 日志解读——GC 日志格式与关键指标;GC 调优方法论——常见问题的调优思路;内存泄漏排查——堆转储分析;堆转储分析工具——MAT 使用指南。

JIT 编译与 AOT

如果你对「Java 代码是怎么变成机器码的」感到好奇,这里会给你答案。

原理执行引擎概述——解释器与编译器;字节码基础——Class 文件结构;C1/C2 编译器——Client 编译器与 Server 编译器;分层编译——启动性能与峰值性能的平衡。

核心优化热点检测——哪些代码会被 JIT 编译;方法内联——最重要的优化;逃逸分析——标量替换与栈上分配;锁优化——锁消除、锁粗化。

AOTAOT 编译——jaotc 与预编译;GraalVM——高性能多语言虚拟机;Native Image——Spring Native 与启动优化;CDS/AppCDS——类数据共享加速启动。

I/O 模型

如果你要构建高性能网络应用,这里是必读的。

基础I/O 模型概述——BIO/NIO/AIO 的演进;阻塞 I/O(BIO)——经典模式与局限;非阻塞 I/O(NIO)——Channel/Buffer/Selector 核心抽象;I/O 多路复用——select/poll/epoll 的演进。

高级特性零拷贝原理——mmap/sendfile;直接内存——堆外内存的使用;Netty 深度解析——高性能网络框架;Netty 线程模型——Boss Group 与 Worker Group。

性能剖析

如果你不知道工具怎么用,从这里开始。

工具Arthas——阿里开源的诊断利器;JFR——JDK Flight Recorder;JMC——JDK Mission Control;火焰图——CPU 性能分析的可视化方法;Continuous Profiling——持续性能剖析。

实战案例CPU 性能问题排查GC 问题排查内存问题排查延迟问题排查死锁问题排查

学习路线建议

flowchart LR
    A["阶段一\n打基础"] --> B["阶段二\n攻并发"]
    B --> C["阶段三\n战 GC"]
    C --> D["阶段四\n攻 I/O"]
    D --> E["阶段五\n炼工具"]

    A --> A1["性能指标基础"]
    A1 --> A2["JVM 内存区域"]

    B --> B1["JMM 与 happens-before"]
    B1 --> B2["synchronized 原理"]
    B2 --> B3["AQS 框架"]
    B3 --> B4["虚拟线程"]

    C --> C1["GC 算法基础"]
    C1 --> C2["G1 收集器"]
    C2 --> C3["ZGC 深度解析"]
    C3 --> C4["GC 日志解读"]

    D --> D1["NIO 核心概念"]
    D1 --> D2["I/O 多路复用"]
    D2 --> D3["Netty 深度解析"]

    E --> E1["Arthas 诊断"]
    E1 --> E2["JFR 分析"]
    E2 --> E3["火焰图"]

入门路线(希望快速解决生产问题):

JVM 内存区域 → G1 收集器 → GC 日志解读 → JMM 基础 → synchronized 原理 → Arthas 诊断

进阶路线(希望深入理解底层机制):

JIT 编译优化 → 逃逸分析 → ZGC 染色指针 → AOT 编译 → GraalVM

专家路线(希望成为性能领域的专家):

I/O 多路复用 → Netty 深度调优 → Continuous Profiling → GC 调优方法论 → 性能问题系统性排查

准备好了吗?让我们从性能指标的基础概念开始,建立正确的性能度量思维。