我正在编写一个微基准来比较使用+运算符与StringBuilder的字符串连接。为此,我创建了一个基于OpenJDK 示例的 JMH 基准测试类,该示例使用了batchSize参数:
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@Measurement(batchSize = 10000, iterations = 10)
@Warmup(batchSize = 10000, iterations = 10)
@Fork(1)
public class StringConcatenationBenchmark {
private String string;
private StringBuilder stringBuilder;
@Setup(Level.Iteration)
public void setup() {
string = "";
stringBuilder = new StringBuilder();
}
@Benchmark
public void stringConcatenation() {
string += "some more data";
}
@Benchmark
public void stringBuilderConcatenation() {
stringBuilder.append("some more data");
}
}
当我运行基准测试时,我收到以下stringBuilderConcatenation
方法错误:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:421)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at link.pellegrino.string_concatenation.StringConcatenationBenchmark.stringBuilderConcatenation(StringConcatenationBenchmark.java:29)
at link.pellegrino.string_concatenation.generated.StringConcatenationBenchmark_stringBuilderConcatenation.stringBuilderConcatenation_avgt_jmhStub(StringConcatenationBenchmark_stringBuilderConcatenation.java:165)
at link.pellegrino.string_concatenation.generated.StringConcatenationBenchmark_stringBuilderConcatenation.stringBuilderConcatenation_AverageTime(StringConcatenationBenchmark_stringBuilderConcatenation.java:130)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:430)
at org.openjdk.jmh.runner.BenchmarkHandler$BenchmarkTask.call(BenchmarkHandler.java:412)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
我在想必须增加默认的 JVM 堆大小,所以我尝试使用JMH 提供的选项允许最多 10GB 的-Xmx10G
值。-jvmArgs
不幸的是,我仍然得到错误。
因此,我尝试将batchSize
参数的值减小到1,但仍然得到OutOfMemoryError。
我发现的唯一解决方法是将基准模式设置为Mode.SingleShotTime
. 由于这种模式似乎将批处理视为单次拍摄(即使s/op显示在 Units 列中),似乎我得到了我想要的指标:执行一组批处理操作的平均时间。但是,我仍然不明白为什么它不能与Mode.AverageTime
.
另请注意,stringConcatenation
无论使用何种基准模式,方法的基准都会按预期工作。该问题仅发生在stringBuilderConcatenation
使用 StringBuilder 的方法上。
欢迎任何帮助理解为什么前面的示例无法使用设置为的基准模式Mode.AverageTime
。
我使用的 JMH 版本是1.10.4。