Dlaczego Łańcuch StringBuilder ma wzór sb.append(x).Dołącz(y) szybciej niż zwykły sb.append( x); sb.Dołącz(y)?

Mam mikrobenchmark, który pokazuje bardzo dziwne wyniki:

@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 Chaining {

    private String a1 = "111111111111111111111111";
    private String a2 = "222222222222222222222222";
    private String a3 = "333333333333333333333333";

    @Benchmark
    public String typicalChaining() {
        return new StringBuilder().append(a1).append(a2).append(a3).toString();
    }

    @Benchmark
    public String noChaining() {
        StringBuilder sb = new StringBuilder();
        sb.append(a1);
        sb.append(a2);
        sb.append(a3);
        return sb.toString();
    }
}

Spodziewam się, że wyniki obu testów będą takie same lub przynajmniej bardzo zbliżone. Jednak różnica jest prawie 5x:

# Run complete. Total time: 00:01:41

Benchmark                  Mode  Cnt      Score     Error  Units
Chaining.noChaining       thrpt   40   8538.236 ± 209.924  ops/s
Chaining.typicalChaining  thrpt   40  36729.523 ± 988.936  ops/s
Czy ktoś wie jak to jest możliwe?
Author: Eugene, 2017-06-02

1 answers

String concatenation a + b + c jest bardzo częstym wzorcem w programach Java, więc HotSpot JVM ma dla niego specjalną optymalizację: -XX:+OptimizeStringConcat, która jest domyślnie włączona.

HotSpot JVM rozpoznaje wzorzec new StringBuilder().append()...append().toString() w kodzie bajtowym i tłumaczy go na zoptymalizowany kod maszynowy bez wywoływania rzeczywistych metod Javy i bez przydzielania obiektów pośrednich. Jest to rodzaj złożonego JVM wewnętrznego.

Oto kod źródłowy do tej optymalizacji.

Po drugiej stronie, sb.append(); sb.append(); ... nie jest obsługiwany specjalnie. Sekwencja ta jest kompilowana tak jak zwykłe wywołania metody Java.

Jeśli powtórzysz test z -XX:-OptimizeStringConcat, wydajność będzie taka sama dla obu wariantów.

 51
Author: apangin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-03 01:19:59