Scala StringBuilder vs Java StringBuilder Performance

Yet another post about performance and microbenchmarks. Yes, I know.

Very small JMH benchmark:

@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(value = 2, jvmArgs = Array("-Xmx2G"))
@Measurement(iterations = 7, time = 3, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 3, time = 3, timeUnit = TimeUnit.SECONDS)
class StringBuilderBenchmark {

@Benchmark
def javaStringBuilder: String = {
new java.lang.StringBuilder().append("abc").append("def")
.toString
}

@Benchmark
def javaStringBuilder2: String = {
new java.lang.StringBuilder().append(495-char-length-string).append(495-char-length-string).toString
}
  @Benchmark
def scalaStringBuilder: String = {
new scala.collection.mutable.StringBuilder().append("abc")
.append("def").toString
}
@Benchmark
def scalaStringBuilder: String = {
new scala.collection.mutable.StringBuilder().append(495-char-length-string).append(495-char-length-string).toString
}
}

And the result:

Benchmark            Mode  Cnt    Score   Error  Units
javaStringBuilder avgt 14 8.754 ± 0.465 ns/op
javaStringBuilder2 avgt 14 237.280 ± 0.828 ns/op
scalaStringBuilder avgt 14 27.299 ± 0.096 ns/op
scalaStringBuilder2 avgt 14 720.742 ± 3.528 ns/op

Wow. Apparently, JVM doesn’t do some optimization over wrapped StringBuilder. I’ve noticed this performance degradation on a more complex test, so, I don’t think it’s just about “microbenchmarking is evil”.

The saddest part, that Scala developers “suffer” just to have StringBuilder as a collection. But do we really need collection features from it? I doubt it.

Source code is on GitHub.