Por qué el patrón de encadenamiento StringBuilder es sb.append (x).añadir (y) más rápido que sb normal.append (x); sb.añadir (y)?


Tengo una marca microbench que muestra resultados muy extraños:

@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();
    }
}

Espero que los resultados de ambas pruebas sean los mismos o al menos muy cercanos. Sin embargo, la diferencia es casi 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

¿Alguien sabe cómo es posible?

Author: Eugene, 2017-06-02

1 answers

La concatenación de cadenas a + b + c es un patrón muy frecuente en los programas Java, por lo que HotSpot JVM tiene una optimización especial para ello: -XX:+OptimizeStringConcat que está activada por defecto.

HotSpot JVM reconoce new StringBuilder().append()...append().toString() pattern en el bytecode y lo traduce al código máquina optimizado sin llamar a métodos Java reales y sin asignar objetos intermedios. Es decir, este es un tipo de compuesto JVM intrínseco.

Aquí está el código fuente para esta optimización.

En el otro lado, sb.append(); sb.append(); ... no se maneja especialmente. Esta secuencia se compila igual que un método Java normal llama.

Si vuelve a ejecutar el benchmark con -XX:-OptimizeStringConcat, el rendimiento será el mismo para ambas variantes.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-03 01:19:59