27 votes

Quand l'optimisation de Javac StringBuilder/StringBuffer a-t-elle été introduite ?

Je sais que le compilateur Javac est capable de transformer la concaténation de String + en utilisant StringBuilder / StringBuffer et je suis curieux de savoir à partir de quelle version ce changement a été introduit ?

J'utilise cet exemple de code :

public class Main {
  public static void main(String[] args) {
      String a = args[0];
      String s = "a";
      s = s + a;
      s = s + "b";
      s = s + "c";
      s = s + "d";
      s = s + "e";
      System.out.println(s);
  }
}

Jusqu'à présent, j'ai essayé avec javac 1.8.0_121 , javac 1.6.0_20 , javac 1.5.0_22 y java 1.4.2_19 .

Voici un exemple du bytecode que je vois utiliser javap -c de 1.4.2_19 :

6:  astore_2
7:  new #3; //class StringBuffer
10: dup
11: invokespecial   #4; //Method java/lang/StringBuffer."<init>":()V
14: aload_2
15: invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
18: aload_1
19: invokevirtual   #5; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual   #6; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;

Les 4 versions semblent utiliser l'optimisation StringBuilder/StringBuffer, donc je suis curieux de savoir à partir de quelle version de Javac ce changement a été introduit ?

31voto

manouti Points 10398

Voici une citation de la spécification du langage à partir de la version 1 :

Une mise en œuvre peut choisir d'effectuer la conversion et la concaténation en une seule étape afin d'éviter de créer puis de rejeter un fichier intermédiaire. String objet. Pour augmenter les performances de la concaténation répétée de chaînes de caractères, un compilateur Java peut utiliser la fonction StringBuffer classe (§20.13) ou une technique similaire pour réduire le nombre de classes intermédiaires. String qui sont créés par l'évaluation d'une expression.

A l'époque, ils avaient StringBuffer au lieu de StringBuilder .

Également une citation de StringBuffer de JDK1.0.2 :

Cette classe est un tampon évolutif pour les personnages. Elle est principalement utilisée pour créer des chaînes de caractères. Le compilateur l'utilise pour implémenter l'opérateur "+".

11voto

lukeg Points 1607

J'ai consulté la spécification du langage Java, première édition (de 1996). Pas facile à trouver, mais c'est ici . Le passage sur l'optimisation de la concaténation était déjà présent à l'époque :

Une implémentation peut choisir d'effectuer la conversion et la concaténation en une seule étape afin d'éviter la création puis la mise au rebut d'un objet String intermédiaire. Pour améliorer les performances de la concaténation répétée de chaînes de caractères, un compilateur Java peut utiliser la classe StringBuffer (§20.13) ou une technique similaire pour réduire le nombre d'objets String intermédiaires créés par l'évaluation d'une expression.

Le cahier des charges portait sur StringBuffer alors, mais StringBuilder (à laquelle la formulation actuelle de JLS fait référence) pourrait être considérée comme plus performante parce que ses méthodes ne sont pas synchronisées.

Cela ne signifie toutefois pas qu'il faut se fier à l'optimisation comme siempre étant en place. La concaténation de chaînes de caractères dans les boucles ne sera pas optimisée, par exemple.

5voto

Shubham Chaurasia Points 1143

JLS a déjà été donné dans certaines réponses. Je veux juste faire remarquer que StringBuffer ( https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html ) existait depuis la version 1.0 alors que

StringBuilder( https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html ) est arrivé dans la version 1.5. Veuillez consulter le since: dans les javadocs respectifs.

5voto

Eugene Points 6271

Cela ne répond pas à la question mais je veux simplement ajouter à l'ensemble du point que dans jdk-9 cette StringBuilder::append est l'une des stratégies autorisées mais pas celle par défaut.

private enum Strategy {
   /**
    * Bytecode generator, calling into {@link java.lang.StringBuilder}.
    */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
     BC_SB_SIZED_EXACT,

   /**
    * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
    * This strategy also tries to estimate the required storage.
    */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
     MH_INLINE_SIZED_EXACT
}

C'est en fait un invokedynamic pour la concaténation de chaînes de caractères, donc son implémentation est maintenant spécifique au JRE, et non au compilateur. La stratégie par défaut est : MH_INLINE_SIZED_EXACT

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X