为了账号安全,请及时绑定邮箱和手机立即绑定

为什么.toString()似乎为StringBuilder修复了OutOfMemoryError

为什么.toString()似乎为StringBuilder修复了OutOfMemoryError

慕勒3428872 2021-05-05 13:26:54
我正在学习如何使用JMH对事物进行微基准测试。我从看似简单的内容开始:StringBuildervs的字符串连接String +=。据我了解,我应该制作一个State包含的实例的对象,StringBuilder因为我不想对其构造函数进行基准测试(无论如何,我也不想每次迭代都为空)。这同样适用于String +=测试-我想String在我的对象State与新的字符串并置。这是我的代码:@State(Scope.Thread)@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)public class Test {    @State(Scope.Thread)    public static class BenchmarkState {        public StringBuilder    builder;        public String           regularString;        @Setup(Level.Iteration)        public void setup() {            builder         = new StringBuilder();            regularString   = "";        }    }    @Benchmark    public String stringTest(BenchmarkState state) {        state.regularString += "hello";        return state.regularString;    }    @Benchmark    public String stringBuilderTest(BenchmarkState state) {        state.builder.append("hello");        return state.builder.toString();    }    public static void main(String[] args) throws RunnerException {        Options opt = new OptionsBuilder()                .include(Test.class.getSimpleName())                .forks(1)                .timeUnit(TimeUnit.MILLISECONDS)                .mode(Mode.Throughput)                .measurementTime(TimeValue.seconds(10))                .build();        new Runner(opt).run();    }}它有效,但是我在想-我不想.toString()在每次迭代结束时都调用。我仅测试串联。因此,我决定通过返回null而将其删除。但是,这是在第一次热身迭代期间发生的:java.lang.OutOfMemoryError: Java heap space    at java.util.Arrays.copyOf(Arrays.java:3332)    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)    at java.lang.StringBuilder.append(StringBuilder.java:136)我知道,如果JMHStringBuilder尽可能快地追加,我将很快耗尽内存,因此我对这个OutOfMemoryError问题并不感到惊讶。但是我不明白为什么要builder.toString()修复它。所以我的问题是:为什么要builder.toString()避免出现OutOfMemoryError问题?StringBuilder还是不将所有字符都保留在内存中吗?假设我既不希望StringBuilder的构造.toString()方法也不希望其 方法成为基准测试的一部分,那么如何正确编写此测试?
查看完整描述

1 回答

?
扬帆大鱼

TA贡献1799条经验 获得超9个赞

调用toString()会花费时间,并产生垃圾,这需要运行GC,从而进一步降低了代码的速度。

由于测试是有时间限制的,因此这些减速可能会导致测试在消耗所有内存之前停止。如果增加时间限制,即使使用,代码也可能因OOM而失败toString,这只会花费很多时间。


查看完整回答
反对 回复 2021-05-19
  • 1 回答
  • 0 关注
  • 371 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信