- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在编写一个微型基准测试来比较使用 + 运算符与 StringBuilder 的字符串串联。为此,我创建了一个基于 OpenJDK example that uses the batchSize parameter 的 JMH 基准测试类。 :
@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 堆大小必须增加,所以我尝试使用 -Xmx10G
值和 JMH 提供的 -jvmArgs
选项允许最多 10GB .不幸的是,我仍然收到错误。
因此,我尝试将 batchSize
参数的值减小到 1,但我仍然遇到 OutOfMemoryError。
我发现的唯一解决方法是将基准模式设置为 Mode.SingleShotTime
。由于此模式似乎将批处理视为单次拍摄(即使 s/op 显示在 Units 列中),似乎我得到了我想要的指标:执行集合的平均时间的批量操作。但是,我仍然不明白为什么它不能与 Mode.AverageTime
一起使用。
另请注意,无论使用何种基准测试模式,stringConcatenation
方法的基准测试都按预期工作。该问题仅发生在使用 StringBuilder 的 stringBuilderConcatenation
方法中。
欢迎提供任何有助于理解为什么前面的示例不能使用设置为 Mode.AverageTime
的基准模式的帮助。
我使用的 JMH 版本是 1.10.4。
最佳答案
您说得对,Mode.SingleShotTime
正是您所需要的:它测量单个批处理的时间。使用 Mode.AverageTime
时,您的迭代仍然有效,直到迭代时间结束(默认为 1 秒)。它测量的是每次执行单个批处理的时间(只计算在执行时间内完全完成的批处理),所以最终结果不同,但执行时间是相同的。
另一个问题是 @Setup(Level.Iteration)
强制设置在每次迭代之前执行,但不是在每个批处理之前执行。因此,您的字符串实际上不受批量大小的限制。字符串版本不会导致 OutOfMemoryError
只是因为它比 StringBuilder
慢得多,所以在 1 秒内它能够构建更短的字符串。
修复基准测试的不太好的方法(同时仍然使用平均时间模式和 batchSize 参数)是手动重置 string/stringBuilder:
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Measurement(batchSize = 10000, iterations = 10)
@Warmup(batchSize = 10000, iterations = 10)
@Fork(1)
public class StringConcatenationBenchmark {
private static final String S = "some more data";
private static final int maxLen = S.length()*10000;
private String string;
private StringBuilder stringBuilder;
@Setup(Level.Iteration)
public void setup() {
string = "";
stringBuilder = new StringBuilder();
}
@Benchmark
public void stringConcatenation() {
if(string.length() >= maxLen) string = "";
string += S;
}
@Benchmark
public void stringBuilderConcatenation() {
if(stringBuilder.length() >= maxLen) stringBuilder = new StringBuilder();
stringBuilder.append(S);
}
}
这是我盒子上的结果(i5 3340、4Gb RAM、64 位 Win7、JDK 1.8.0_45):
Benchmark Mode Cnt Score Error Units
stringBuilderConcatenation avgt 10 145.997 ± 2.301 us/op
stringConcatenation avgt 10 324878.341 ± 39824.738 us/op
因此您可以看到只有大约 3 个批处理适合 stringConcatenation
(1e6/324878
) 的第二个批处理,而对于 stringBuilderConcatenation
则可以有数千个批处理被执行导致巨大的字符串导致 OutOfMemoryError
。
我不知道为什么添加更多内存对您不起作用,对我来说 -Xmx4G
足以运行原始基准测试的 stringBuilder 测试。可能您的盒子速度更快,因此生成的字符串甚至更长。请注意,对于非常大的字符串,即使您有足够的内存,您也可以达到数组大小限制(20 亿个元素)。添加内存后检查异常堆栈跟踪:是否相同?如果达到数组大小限制,它仍将是 OutOfMemoryError
,但堆栈跟踪会有所不同。无论如何,即使有足够的内存,基准测试的结果也会不正确(String
和 StringBuilder
)。
关于java - OutOfMemory 与 JMH 和 Mode.AverageTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32097429/
我在网上找不到关于 here 的任何信息,谁能告诉我 ops/us, Cnt, Score, Error 是什么意思。 最佳答案 ops/us - 每微秒的操作(基准方法执行) Cnt - 试验总数(
我在网上找不到关于 here 的任何信息,谁能告诉我 ops/us, Cnt, Score, Error 是什么意思。 最佳答案 ops/us - 每微秒的操作(基准方法执行) Cnt - 试验总数(
在我的 jmh 课上,我正在使用 @BenchmarkMode(Mode.SampleTime) @Measurement(iterations = 10) @Threads(value = 10)
我已经将其视为微基准测试中的潜在陷阱之一。如果您指定@Measurement(或@Warmup)将运行固定的时间量,这意味着,当比较不同的运行(例如,不同的平台、不同版本的 VM 等)时,您将获得更少
想开始做我从现在开始写的方法的基准测试,有很长一段时间的动力,终于决定从昨天开始这样做。但我对我的设置过程感到震惊。 我已经正确安装了 JMH 插件。 所有导入工作正常。 甚至我的 POM 也没有显示
我正在使用 JMH,但发现有些难以理解:我有一种方法用 @Benchmark 注释。我设置了 measurementIterations(3) .该方法被调用了 3 次,但在每次迭代调用中,该函数运行
假设我有一个带有两个参数的 JMH 测试: @Param( { "1", "2", 4", "8", "16" } ) int param1; @Param( { "1", "2", 4", "8",
我正在使用tutorial学习JMH基准测试。 我注意到here中的功能benchMurmur3_128有2个与预热相关的东西。 因此,我对Fork注释中的热身属性和带有迭代属性的Warmup注释之间
我不明白 JMH 结果中的 score 属性?我也没有在网上找到任何关于它的信息。 谁能告诉我,它是关于什么的?据我所知,高分比低分好,但这究竟是什么意思,它是如何计算的? 最佳答案 JMH 支持以下
官方资源 官方Github样例 应用场景 对要使用的数据结构不确定,不知道谁的性能更好 对历史方法代码重构,要评判改造之后的性能提升多少 ( 我要做的场景 )
我用 JMH 测试我的程序性能。并且无法配置堆大小。我想知道为什么它不起作用。 问题: 为什么 JMH 不接受堆大小配置? JMH 是否在没有 jvmArgs 方法的情况下吸收 idea 堆大小设置?
我正在使用 JMH 对 DOM 解析器进行基准测试。我得到了非常奇怪的结果,因为第一次迭代实际上比后面的迭代运行得更快 谁能解释为什么会发生这种情况?另外,百分位数和所有数字是什么意思,为什么它在第三
我正在对 Spring Boot 应用程序启动时间进行基准测试。完整的项目是here ,这是 WIP,但相关类如下。 抽象基本状态: public abstract class BootAbstrac
我有:这样的方法: @GenerateMicroBenchmark public static void calculateArraySummary(String[] args) { // c
我读到了JMH并尝试了提供的示例。 我想做的是测量以下场景的统计数据, [ 1] client order -> [2] server -> [3] start processing the orde
我正在玩 Math.max 看看它是否受到分支预测的影响(不,至少在 x64 的 JDK 上不是,有一个 cmovl),如果按位实现可以与默认实现竞争。所有测试如下所示: @Threads(4) @S
我在 JMH 中看到一个常见问题 ConstantFold ,但是如果我有逆问题怎么办?我需要静态最终字段作为参数。例如,它可以是某些算法的某个常量变量。但在 java-doc 中我看到: {@lin
我正在尝试一个非常快的方法(~20 us/op),它似乎工作得很好,除了一些随机很长的迭代: Iteration 63: 14.319 us/op Iteration 64: 13.128 us/
我想看看是否有一种方法可以告诉 JMH 仅测量微基准调用的所有方法中的一个特定方法。 我想使用单元测试作为基础自动创建微基准,因此我不必手动构建微基准。在我的研究中,我有一个大型代码库,我在其中进行了
我正在运行 JMH 基准测试: Options opt = new OptionsBuilder() .output("C:/test/infinis
我是一名优秀的程序员,十分优秀!