JMH 性能测试:Java 代码性能对比与优化

JMH(Java Microbenchmark Harness)是专为 Java 设计的微基准测试框架,能精确测量代码片段性能,避免 JVM 优化干扰。以下是关键步骤与优化方法:


1. JMH 核心原理
  • 避免 JIT 干扰:通过多次预热(warmup)和测量(measurement)迭代,消除即时编译影响。
  • 统计稳定性:使用分位数(如 $p_{90}$、$p_{99}$)分析结果分布,而非单一平均值。
  • 模式选择
    • Throughput:单位时间操作次数(ops/ms)
    • AverageTime:单次操作耗时(ms/op)
    • SampleTime:采样执行时间分布

2. 快速搭建基准测试

依赖配置(Maven)

<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.37</version>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.37</version>
</dependency>

示例:对比字符串拼接性能

@BenchmarkMode(Mode.Throughput) // 测试吞吐量
@OutputTimeUnit(TimeUnit.MILLISECONDS) // 输出单位
@State(Scope.Thread)
public class StringBenchmark {

    @Param({"10", "100", "1000"})
    private int length;

    @Benchmark
    public String concatWithPlus() {
        String result = "";
        for (int i = 0; i < length; i++) {
            result += "a"; // 低效拼接
        }
        return result;
    }

    @Benchmark
    public String concatWithBuilder() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append("a"); // 高效拼接
        }
        return sb.toString();
    }
}

运行命令

mvn clean install
java -jar target/benchmarks.jar


3. 性能对比结果分析

输出示例:

Benchmark                 (length)   Mode  Cnt     Score     Error  Units
concatWithPlus                10    thrpt    5  1234.56 ±  67.89  ops/ms
concatWithBuilder             10    thrpt    5  5678.90 ± 123.45  ops/ms
concatWithPlus               100    thrpt    5    12.34 ±   1.23  ops/ms
concatWithBuilder            100    thrpt    5   456.78 ±  45.67  ops/ms

结论

  • 短字符串(length=10):StringBuilder 吞吐量是 + 的 $\approx 4.6$ 倍
  • 长字符串(length=100):StringBuilder 吞吐量是 + 的 $\approx 37$ 倍
  • 优化方向:避免在循环中使用 + 拼接字符串。

4. 常见优化策略
  • 减少对象分配:重用对象(如 ThreadLocal 缓存),降低 GC 压力。
  • 分支预测优化:避免循环内复杂条件判断,例如用查表法替代 switch-case
  • 内存局部性:优化数据结构(如将 LinkedList 替换为 ArrayList),提升 CPU 缓存命中率。
  • 内联小方法:使用 final 方法或 JVM 参数 -XX:InlineSmallCode=...

5. 注意事项
  • 避免死代码消除:用 Blackhole 消费计算结果,防止 JIT 删除未使用代码。
  • 控制环境变量:在固定 CPU 频率、关闭其他进程的机器上运行。
  • 结果解读:关注误差范围(± Error),若重叠则性能差异不显著。

关键工具

  • jmh-visualizer:图形化分析结果
  • async-profiler:定位热点方法
  • -prof gc:监控测试期间的 GC 行为

通过 JMH 量化优化效果,可系统性地提升 Java 代码性能。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐