title: Why does .toString() seem to fix an OutOfMemoryError exception for StringBuilder?
body: <p>I am learning how to microbenchmark things with JMH. I started with something seemingly simple: string concatenation for <code>StringBuilder</code> vs <code>String +=</code>.</p>
  
  <p>From my understanding, I should make a <code>State</code> object that contains an instance of <code>StringBuilder</code> because I don't want to benchmark its constructor (nor do I want to an empty one every iteration anyway). Same goes for the <code>String +=</code> test - I want a <code>String</code> object in my <code>State</code> to be concatenated with new strings.</p>
  
  <p>This is my code:</p>
  
  <pre><code>@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();
      }
  
  }
  </code></pre>
  
  <p>It works, but I was thinking - I don't want to call <code>.toString()</code> at the end of every iteration. I am testing concatenation only. So I decided to remove it by just returning <code>null</code> instead.</p>
  
  <p>But then, this happens during the first warmup iteration:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>I understand that I would run out of memory pretty quickly if JMH is appending to <code>StringBuilder</code> as fast as it can, so I'm not surprised by the <code>OutOfMemoryError</code> issue. But I don't understand why does <code>builder.toString()</code> fix it.</p>
  
  <p>So my questions are:</p>
  
  <ul>
  <li><p>Why does <code>builder.toString()</code> avoid an <code>OutOfMemoryError</code> issue? Doesn't <code>StringBuilder</code> still keep all the characters in memory regardless?</p></li>
  <li><p>Assuming that I do NOT want neither <code>StringBuilder</code>'s constructor nor its  <code>.toString()</code> method to be part of the benchmark, how do I properly write this test?</p></li>
  </ul>