IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Combien de variable de type String sont instanciées à chaque exécution ?


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 910
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 910
    Par défaut Combien de variable de type String sont instanciées à chaque exécution ?
    Salut,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import java.util.*;
    import java.lang.*;
    import java.io.*;
     
    class Ideone
    {
        public static void main (String[] args) throws java.lang.Exception
        {
        String str = new String("") ;
        for(int i = 0; i < 10; i++) 
              str += "i = " + i + " i² = " + i*i + "\n";
          System.out.println(str);
     
        }
    }
    Combien de variable de type String sont instanciées à chaque exécution de la ligne 11 ?

    Une seule ? Une pour chaque addition ?

    Merci.

  2. #2
    Membre chevronné
    Avatar de provirus
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2009
    Messages
    248
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Canada

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2009
    Messages : 248
    Par défaut
    Bonjour,

    la réponse est: énormément
    Chaque nouveau String est une instanciation. Par contre, 2 fois la même chaine est la même instance (en d'autres mots, si tu as 3 Strings: "allo", "monde" et "allo", tu as 2 instances au total puisque "allo" va pointer sur la même instance).

    En partant de là, voici les instances en ordre (de haut en bas et de droite à gauche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    1- "" (dans str)
    2- "\n"
    3- "0\n"
    4- " i² = 0\n"
    5- "0 i² = 0\n"
    6- "i = 0 i² = 0\n" (str à la fin de la boucle)
     
    (fin de la première boucle et on est déjà à 6)
    2- "\n" (c'est la même que la #2)
    7- "1\n"
    8- " i² = 1\n"
    9- "1 i² = 1\n"
    10- "i = 1 i² = 1\n" 
    11- "i = 0 i² = 0\ni = 1 i² = 1\n" (str à la fin de la boucle)
     
    (fin de la deuxième boucle et ça continue...)
    Pour éviter tout cela, le mieux est d'utiliser un StringBuilder.

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    De variable String ? Aucune. On n'instancie pas une variable, on instancie une classe.

    Si la question est, combien d'objets de type String sont construits à chaque exécution de la ligne 11, eh bien, chose rare en Java, ça dépend des choix du compilateur.

    La règle de base, décrit deux temps :
    #1 - convertir chaque opérande de la concaténation en String. Ici il n'y en a que deux qui ne sont pas des String : i et i*i. Ça fait déjà deux String à chaque exécution.
    #2 - chaque opération de concaténation entre deux opérandes, crée une nouvelle String résultat. Ici nous avons 5 signes + donc 5 concaténations, donc création de 5 Strings.
    Au total ça devrait faire 7.

    Mais pour des raisons d'optimisation une certaine liberté est laissée au compilateur. La String résultante calculée par l'expression, doit être équivalente à ce que produiraient les règles énoncées. Mais le compilateur n'est pas tenu de réellement créer les String en question, et peut décider à la place d'utiliser d'autres techniques pour générer moins d'objets intermédiaires, puisque ces objets sont de toute façon inaccessibles et sans usage en dehors des étapes de calcul.

    Ainsi un compilateur a le droit de faire les conversions et concaténations en une seule étape, par exemple en usant d'un StringBuilder intermédiaire.
    Ce qui ne crée qu'une seule String, pour stocker le résultat dans la variable.

    Si nous regardons comment le compilateur javac 1.8 d'Oracle compile ce bout de code, nous voyons qu'il instancie en effet un StringBuilder, et qu'il appelle append(String) et append(int) dessus. Puis la String finale est générée avec un appel à toString() sur ce StringBuilder, ce qui crée donc une String. Une seule.
    Reste à voir si les appels à append(int) n'en créeraient pas aussi. Cela ne dépend pas du compilateur, mais de la JRE : plus exactement de l'implémentation de StringBuilder. Si nous regardons celle de la JRE 1.8 d'Oracle, nous voyons que append(int) ne crée pas de String : à la place il calcule les chiffres du nombre et les ajoute à la volée dans le StringBuilder avec des accès optimisés.


    Conclusion : avec le compilateur et la JRE 1.8 d'Oracle, il n'y a création que d'une seule String à la ligne 11.
    D'autres compilateurs et d'autres JRE pourraient donner d'autres résultats.

    Mon conseil : il n'y a pas lieu de penser que les autres feraient beaucoup moins bien. Appeler StringBuilder est une évidence et il n'y a pas de raison de croire qu'un compilateur n'y aurait pas pensé.
    Si la concaténation est en une seule expression, on peut raisonnablement compter sur le compilateur pour optimiser l'opération correctement.
    Par contre, si elle est en plusieurs instructions, le compilateur n'est pas autorisé à adapter son comportement et il vaut mieux, soit se ramener à une seule expression, soit utiliser StringBuilder soi-même.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par thelvin Voir le message
    Conclusion : avec le compilateur et la JRE 1.8 d'Oracle, il n'y a création que d'une seule String à la ligne 11.
    Il y a bien une seule String créé à la ligne 11... mais comme cette ligne est à l'intérieur d'une boucle cela va générer plusieurs String (et même plusieurs StringBuilder), ce qui se révèle très consommateur en mémoire !
    Bien sûr sur 10 itérations c'est quasi invisible... mais cela monte de manière exponentielle avec le nombre d'itération.

    En effet chaque iteration va créer deux objets : un StringBuilder et un String.
    Du coup on ne profite pas de la capacité du StringBuilder à se dimensionner correctement, puisqu'on en crée un nouveau à chaque fois.
    C'est comme si on avait écrit ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    String str = "";
    for(int i = 0; i < 10; i++) 
        str = new StringBuilder(str).append("i = ").append(i).append(" i² = ").append(i*i).append("\n").toString();

    Bref il vaut mieux utiliser un seul StringBuilder comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	StringBuilder sb = new StringBuilder();
    	for(int i = 0; i < 10; i++)
    	    sb.append("i = ").append(i).append(" i² = ").append(i*i).append("\n");
    	String str = sb.toString();

    Pour info, en calculant le temps d'exécution j'obtiens les résultats suivant (StringBuilder / opérateur +) :
    • 1 000 itérations : 1ms / 31ms
    • 10 000 itérations : 9ms / 1,5s
    • 100 000 itérations : 37ms / 167s (près de 3 minutes)
    • 1 000 000 itérations : 128ms / (je n'ai pas eu le courage d'attendre).
    • 10 000 000 itérations : 1,2s / (je n'ai pas eu le courage d'attendre).



    a++

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Beginner. Voir le message
    Combien de variable de type String sont instanciées à chaque exécution de la ligne 11 ?
    Une seule ? Une pour chaque addition ?
    Si je me réfère à la question, sauf erreur de ma part, la réponse devrait être : une pour chaque addition

    Mais en tenant compte de l'optimisation du compilateur, ça pourrait aussi être une seule (s'il a généré les opérations sur un StringBuilder ou équivalent)
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Mais en tenant compte de l'optimisation du compilateur, ça pourrait aussi être une seule (s'il a généré les opérations sur un StringBuilder ou équivalent)
    Un compilateur qui utiliserait un seul StringBuilder sur une boucle for ? Ca me semble étonnant. Et dans tous les cas possible uniquement sur des exemples tres simples...

  7. #7
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    La compilation du code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public static void main(String[] args)
    {
            String str = new String("");
     
            for (int i = 0; i < 10; i++)
            {
                str += "i = " + i + " i² = " + i * i + "\n";
            }
            System.out.println(str);
    }
    Donne le résultat (décompilé à partir du .class)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public static void main(String args[])
    {
            String str = new String("");
            for(int i = 0; i < 10; i++)
                str = (new StringBuilder(String.valueOf(str))).append("i = ").append(i).append(" i\262 = ").append(i * i).append("\n").toString();
     
            System.out.println(str);
    }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre Expert
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Par défaut
    ok. Donc, comme attendu, on a bien un StringBuilder par iteration (et non un seul utilisé sur la boucle for). Et on va retrouver la consommation mémoire et le temps d'execution donnés par adiGuba...

  9. #9
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    D'un point de vue de l'optimisation, le mieux serait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10; i++)
    {
        sb.append("i = ").append(i).append(" i² = ").append(i * i).append("\n");
    }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. convertir une variable de type String en Number
    Par lilbrother974 dans le forum Flash
    Réponses: 13
    Dernier message: 06/09/2006, 08h28
  2. fonction replace et variable de type string
    Par aA189 dans le forum Access
    Réponses: 6
    Dernier message: 11/08/2006, 17h38
  3. [VB] gestion des couleurs des variables de type string
    Par landry005 dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 28/03/2006, 14h36
  4. Ajouter a une variable de type string, un entier
    Par Little-Freud dans le forum SL & STL
    Réponses: 12
    Dernier message: 05/03/2005, 19h33
  5. [VB6] creation de variable de type string dynamiquement
    Par da40 dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 12/06/2003, 16h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo