Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is String concatenation faster than String.valueOf for converting an Integer to a String?

Tags:

I have a benchmark :

@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
@Measurement(iterations = 40, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
public class StringConcatTest {

    private int aInt;

    @Setup
    public void prepare() {
        aInt = 100;
    }

    @Benchmark
    public String emptyStringInt() {
        return "" + aInt;
    }

    @Benchmark
    public String valueOfInt() {
        return String.valueOf(aInt);
    }

}

And here is result :

Benchmark                                          Mode  Cnt      Score      Error  Units
StringConcatTest.emptyStringInt                   thrpt   40  66045.741 ± 1306.280  ops/s
StringConcatTest.valueOfInt                       thrpt   40  43947.708 ± 1140.078  ops/s

It shows that concatenating of empty string with integer number is 30% faster than calling String.value(100). I understand that "" + 100 converted to

new StringBuilder().append(100).toString()

and -XX:+OptimizeStringConcat optimization is applied that makes it fast. What I do not understand is why valueOf itself is slower than concatenation. Can someone explain what exactly is happening and why "" + 100 is faster. What magic does OptimizeStringConcat make?

like image 631
Dmitriy Dumanskiy Avatar asked Feb 12 '17 22:02

Dmitriy Dumanskiy


People also ask

What is the difference between string valueOf and integer toString?

You will clearly see that String. valueOf(int) is simply calling Integer. toString(int) for you. Therefore, there is absolutely zero difference, in that they both create a char buffer, walk through the digits in the number, then copy that into a new String and return it (therefore each are creating one String object).

Why is string builder faster?

String is immutable whereas StringBuffer and StringBuilder are mutable classes. StringBuffer is thread-safe and synchronized whereas StringBuilder is not. That's why StringBuilder is faster than StringBuffer.

Why is string concatenation slow?

The reason is that String is immutable; its value does not change. When adding a string, we create a new string in memory. StringBuilder is mutable, so when we use the append, its value changes, not a new string is created. Therefore using StringBuilder will save memory and run faster.


1 Answers

As you've mentioned, HotSpot JVM has -XX:+OptimizeStringConcat optimization that recognizes StringBuilder pattern and replaces it with highly tuned hand-written IR graph, while String.valueOf() relies on general compiler optimizations.

I've found the following key differences by analyzing the generated assembly code:

  • Optimized concat does not zero char[] array created for the result string, while the array created by Integer.toString is cleared after allocation just like any other regular object.
  • Optimized concat translates digits to chars by simple addition of '0' constant, while Integer.getChars uses table lookup with the related array bounds check etc.

There are other minor differences in the implementation of PhaseStringOpts::int_getChars vs. Integer.getChars, but I guess they are not that significant for performance.


BTW, if you take a bigger number (e.g. 1234567890), the performance difference will be negligible because of an extra loop in Integer.getChars that converts two digits at once.

like image 119
apangin Avatar answered Sep 26 '22 01:09

apangin