Using JMH for Java Microbenchmarking: A Comprehensive Guide
This article introduces JMH, explains how to add dependencies, write and run microbenchmarks for string concatenation, describes key annotations, highlights common pitfalls, and shows how to package, visualize, and integrate JMH benchmarks within Java projects.
JMH Introduction
JMH (Java Microbenchmark Harness) is a tool suite for micro‑benchmarking Java code at the method level with nanosecond precision, created by experts who understand JIT and JVM effects on benchmarks.
It is useful when you need to quantify the performance of hotspot methods and compare different implementations.
Adding Dependencies
For JDK 9 and later JMH is bundled; for earlier JDKs add the following Maven dependencies (latest version 1.23):
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.23</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.23</version>
</dependency>Writing a Benchmark
Create a JMH test class to compare string concatenation using the + operator versus StringBuilder.append() :
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 5)
@Threads(4)
@Fork(1)
@State(value = Scope.Benchmark)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class StringConnectTest {
@Param(value = {"10", "50", "100"})
private int length;
@Benchmark
public void testStringAdd(Blackhole blackhole) {
String a = "";
for (int i = 0; i < length; i++) {
a += i;
}
blackhole.consume(a);
}
@Benchmark
public void testStringBuilderAdd(Blackhole blackhole) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(i);
}
blackhole.consume(sb.toString());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(StringConnectTest.class.getSimpleName())
.result("result.json")
.resultFormat(ResultFormatType.JSON).build();
new Runner(opt).run();
}
}The @Benchmark annotation marks methods to be measured; the Blackhole prevents dead‑code elimination.
Running the Benchmark
Execute the benchmark via the generated Runner or package it into an executable JAR using the Maven Shade plugin:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>jmh-demo</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>Then run:
mvn clean install
java -jar target/jmh-demo.jar StringConnectTestJMH Core Annotations
@BenchmarkMode
Specifies the measurement mode, e.g., @BenchmarkMode({Mode.SampleTime, Mode.AverageTime}) or Mode.All .
@State
Defines the scope of shared objects: Scope.Benchmark , Scope.Group , or Scope.Thread .
@OutputTimeUnit
Sets the time unit for results (e.g., TimeUnit.NANOSECONDS ).
@Warmup
Configures warm‑up iterations, time, and batch size to let the JVM JIT optimise the code before measurement.
@Measurement
Configures the actual measurement iterations; parameters are similar to @Warmup .
@Threads
Specifies how many threads run the benchmark concurrently.
@Fork
Controls how many separate JVM processes are launched for isolation.
@Param
Provides a set of values for a field, enabling parameterised benchmarks.
Common Pitfalls
Avoid dead‑code elimination by using Blackhole.consume() or returning the result; beware of constant folding, inlining, false sharing, and other JVM optimisations that can skew results.
JMH Plugins and IDE Integration
IntelliJ IDEA offers a JMH plugin that can generate benchmark methods, run individual benchmarks, or execute all annotated methods directly from the IDE.
Visualization
Exported JSON results can be visualised with tools such as JMH Visual Chart or JMH Visualizer .
Conclusion
JMH provides a reliable way to benchmark Java code while mitigating JIT and JVM optimisation effects; by annotating methods with @Benchmark and configuring the harness appropriately, developers can obtain accurate performance metrics for their business logic.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.