Maven基准测试配置报错:无法加载org.openjdk.jmh.runner.ForkedMain类
JMH基准测试Maven Profile执行时出现ClassNotFoundException: org.openjdk.jmh.runner.ForkedMain
问题场景
我在Maven中创建了一个Profile,期望通过mvn verify -Dbenchmark运行所有JMH基准测试,配置如下:
<profiles> <profile> <id>benchmark</id> <activation> <property> <name>benchmark</name> </property> </activation> <properties> <benchmark.report>false</benchmark.report> </properties> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> <execution> <phase>verify</phase> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>org.openjdk.jmh.Main</mainClass> <arguments>.*</arguments> <classpathScope>test</classpathScope> </configuration> </plugin> </plugins> </build> </profile> </profiles>
执行时抛出以下异常:
Caused by: java.lang.ClassNotFoundException: org.openjdk.jmh.runner.ForkedMain <forked VM failed with exit code 1> <stdout last='20 lines'> </stdout> <stderr last='20 lines'> Error: Could not find or load main class org.openjdk.jmh.runner.ForkedMain Caused by: java.lang.ClassNotFoundException: org.openjdk.jmh.runner.ForkedMain </stderr>
单独运行基准测试无异常,设置classpathScope为test是为了找到分散的META-INF/benchmarklist文件。
原因分析
这个异常的核心问题是JMH默认会fork子进程运行基准测试,但exec-maven-plugin的配置只保证了主进程的类路径包含test依赖和JMH库,fork出来的子进程无法继承完整的类路径:
- 当通过
org.openjdk.jmh.Main启动基准测试时,JMH会自动创建子进程(ForkedMain)隔离测试环境,避免主进程的JVM参数、已有线程影响测试结果 - exec-maven-plugin的
classpathScope仅作用于主进程,子进程的类路径未被正确配置,导致找不到org.openjdk.jmh.runner.ForkedMain类 - 单独运行时类路径完整,不存在该问题,但通过exec插件启动时,fork子进程的类路径未包含JMH核心依赖
解决方案
方案1:改用JMH官方Maven插件(推荐)
JMH官方提供的jmh-maven-plugin专门处理基准测试的类路径、fork逻辑,无需手动维护子进程的类路径:
<profiles> <profile> <id>benchmark</id> <activation> <property> <name>benchmark</name> </property> </activation> <build> <plugins> <plugin> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-maven-plugin</artifactId> <version>1.37</version> <!-- 替换为最新稳定版 --> <executions> <execution> <phase>verify</phase> <goals> <goal>benchmark</goal> </goals> </execution> </executions> <configuration> <includes>.*</includes> <!-- 匹配所有基准测试类 --> <classpathScope>test</classpathScope> <!-- 加载test路径下的benchmarklist --> </configuration> </plugin> </plugins> </build> </profile> </profiles>
方案2:修改exec-maven-plugin配置,禁用JMH fork
如果坚持使用exec插件,可以通过JMH参数-f 0禁用fork子进程,让基准测试在主进程运行(注意:这种方式可能影响测试结果准确性,主进程环境可能存在干扰):
<configuration> <mainClass>org.openjdk.jmh.Main</mainClass> <arguments>-f 0 .*</arguments> <!-- 添加-f 0参数禁用fork --> <classpathScope>test</classpathScope> </configuration>
内容的提问来源于stack exchange,提问作者origin
相关产品推荐
相关产品推荐

