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

 C++ Discussion :

Occupation de la mémoire


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Billets dans le blog
    1
    Par défaut Occupation de la mémoire
    Bonjour !

    je n'arrive pas à savoir à quel moment les ressources de l'ordinateur sont occupées.

    J'ai pas mal de textes sous forme de strings dans des fonctions servant à composer différentes interfaces.

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void summary()
    {
        ConsoleLayout cl;//classe dont les fonctions prennent la référence constante d'une string, effectuant seulement des "cout <<" avec differentes mises en page
        cl.title( "Summary" );
        cl.link( 1, "New Work" );
        cl.enter( 2 );
        cl.link( 9, "Options" );
        cl.ending( 0, "Quit" );
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void options()
    {
        ConsoleLayout cl;
        cl.title( "Options" );
        cl.ending( 0, "Summary" );
    }
    Je peux implémenter ces fonctions soit :

    - Dans le fichier source d'une seule classe.
    Les strings seront "chargées" en fonction de l'appel de telle ou telle fonction, ou l'ensemble sera "chargé" à l'appel de la classe ?

    - Dans différentes classes déjà définies
    Là encore les strings seront dans une fonction, elles prendront des ressources seulement à l'appel de cette fonction ?

    - Dans différentes classes définies au besoin par héritage selon l'interface
    Me semble la meilleure solution, mais est-ce que j'y gagne vraiment ?


    Je ne sais pas si j'ai été vraiment clair, mais peut être auriez vous des idées ou des liens pour m'aiguiller ?

    Un grand merci.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,
    A vrai dire, tu n'as pas vraiment à t'inquiéter de cela, car cela rentre vraiment dans l'optimisation prématurée, que tout le monde sait (ou du moins devrait savoir ) être la voie expresse vers tous les problèmes

    Ceci dit, étant donné que je subodore que tu ne te contenteras sans doute pas de cette réponse, je vais essayer d'expliquer clairement ce qui se passe au niveau de la popote interne de ton application (je prendrai sans doute quelques raccourcis, mais c'est surtout pour te faire comprendre le principe )

    D'abord, il faut prendre conscience du fait que, si tu déclares une variable de type std::string sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::string hello("Salut tout le monde");
    cela va se traduire par plusieurs choses au niveau du code binaire de ton application:
    1- Il y aura un "tableau de caractères" contenant "Salut tout le monde" (sans les guillemets ) qui prendra place dans une partie "read only" de ton exécutable (je crois qu'on appelle cette partie le "data segment"... à vérifier ).

    Cela signifie que, si tu ouvres ton binaire avec un éditeurs hexadécimal, ou si tu utilises l'outil strings sous linux, tu pourras parfaitement retrouver cette chaine de caractères "in extenso" quelque part dans le code binaire de ton application.

    2- Il y aura un appel au constructeur de std::string qui accepte un const char *, avec transmission de l'adresse à laquelle se trouve cette chaine de caractères "codée en dur".

    3- le constructeur de std::string utilisera new[] pour obtenir un espace mémoire suffisant pour représenter l'ensemble de la chaine de caractères

    4- le lorsque tu atteins l'accolade fermante du bloc dans lequel ta variable est déclarée, le destructeur de std::string est appelé automatiquement. Ce dernier appelle delete[] sur le pointeur pour faire libérer la mémoire qui avait été allouée précédemment.

    Généralement, on conseille très fermement de transmettre les paramètres comme les std::string sous la forme de référence (éventuellement constante) plutôt que sous la forme de valeur.

    La raison en est que, si tu transmet un paramètre par valeur, tu provoque obligatoirement la copie de l'objet.

    Dans le cas de std::string, cela signifie faire appel à son constructeur de copie, qui ... demandera également l'allocation d'un espace mémoire suffisant pour représenter la chaine de caractères, plus la copie de celle-ci dans l'espace mémoire en question.

    Le passage par référence permet d'éviter cette copie, parce qu'au niveau du code assembleur, une référence est strictement identique à un pointeur (donc, à une valeur numérique entière (généralement) non signée qui représente l'adresse à laquelle le processeur va trouver un objet du type indiqué).

    Seulement, il faut savoir que, lorsqu'un argument est transmis sous la forme d'une référence constante, il permet la création de ce que l'on appelle une "variable temporaire anonyme".

    Autrement dit, lorsque tu invoques ta fonction
    il y aura création d'une variable temporaire (dans le sens où elle n'existe que pour la durée d'exécution de la fonction title) anonyme (car le nom de la variable est inconnu du développeur) qui contient le terme "Summary" qui sera transmise à title.

    C'est à dire que les différentes étapes dont je parlais la tantôt seront exécutées exactement comme ce que je t'ai expliqué .

    Si toutes tes chaines de caractères sont "codées en dur", la variable de type std::string sera créée au moment de l'appel de la fonction à laquelle elle est transmise et détruite au moment où l'exécution de cette fonction atteindra l'accolade fermante (au niveau du processeur, cela correspond à "un tout petit peu avant" que le processeur ne commence à récupérer les données de la fonction appelante ).

    Par contre, si tu transmets une chaine de caractères existante, sous une forme qui pourrait être proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void foo(){
        std::string str("Salut tout le monde");
        /* ... diverse instructions, dont, pourquoi pas, la manipulation de str*/
        if(test){
            cl.title(str);
        }
    }
    la variable str existera entre le moment de sa déclaration (std::string str("Salut tout le monde"); et l'accolade fermante finale de foo().

    Le constructeur de std::string sera appelé au moment de la déclaration de la variable et son destructeur sera appelé au moment où l'on atteint l'accolade fermante

    Note enfin que cette logique se retrouve pour n'importe quelle variable (y compris les variables membres non statiques de classe ) et que la logique est que la création des variables se fait dans l'ordre de leur déclaration et que leur destruction se fait dans l'ordre inverse (parce que l'on travaille réellement sur une "pile" de données )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Jolie explication.

    Un petit détail m'échappe par contre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void f1(const char*);
    void f2(const std::string&);
    void f3(std::string);
     
    f1("abc");
    f2("abc");
    f3("abc");
    Ici, aucune copie pour f1 : juste le passage d'un pointeur,
    1 copie pour f2 : création d'un string temporaire (même si le string est const il y a une allocation mémoire ? En mettant de coté les optimisations pour les string de moins de 16 caractères.)
    1 ou 2 copies pour f3 ? L'objet temporaire est copié, ou directement passé ?

  4. #4
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 760
    Par défaut
    Pour f2 il y aura effectivement une allocation dynamique. "abc" n'étant pas un std::string, le constructeur de std::string est appelé.
    Pour f3 c'est la même chose. Par contre, le résultat est différent si un std::string est passé:
    - si c'est une référence qui est envoyer (variable non temporaire) alors une copie est faite
    - si c'est une variable temporaire (f3(std::string("abc"))) par exemple) alors ça dépend des optimisations du compilo. Par défaut il y a élision et la copie n'est pas faite. Donc un seul constructeur est appelé.

    À noté quand C++11 il y a le move semantic et le constructeur d'une rvalue (variable temporaire) d'un std::string ne fait pas d'allocation.

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Jolie explication.

    Un petit détail m'échappe par contre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void f1(const char*);
    void f2(const std::string&);
    void f3(std::string);
     
    f1("abc");
    f2("abc");
    f3("abc");
    Ici, aucune copie pour f1 : juste le passage d'un pointeur,
    1 copie pour f2 : création d'un string temporaire (même si le string est const il y a une allocation mémoire ? En mettant de coté les optimisations pour les string de moins de 16 caractères.)
    Sauf exceptions, tu devrais en tout cas estimer que c'est le cas.

    Il n'est pas impossible qu'il puisse exister une spécialisation quelconque qui tende à optimiser la création de petites chaines de caractères (mettons, moins de 8 ) pour utiliser un tableau de taille fixe, sans allocation dynamique, plutôt que pour utiliser un tableau alloué de manière dynamique.

    Je ne crois pas que ce soit interdit par la norme, mais je ne sais absolument pas s'il y a un compilateur qui le fait de la sorte
    1 ou 2 copies pour f3 ? L'objet temporaire est copié, ou directement passé ?
    Il y a soit copie, soit création.

    Ce sera le "minimum légal" pour que cela fonctionne.
    tu auras une création si tu fais f3("salut");et une copie si tu fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::string str("salut");
    f3(str);
    Comme l'argument est nommé, la sémantique de mouvement n'est pas applicable au niveau de l'argument, en tous cas .
    Citation Envoyé par jo_link_noir Voir le message
    Pour f2 il y aura effectivement une allocation dynamique. "abc" n'étant pas un std::string, le constructeur de std::string est appelé.
    Pour f3 c'est la même chose.
    Jusque là, je suis d'accord.

    Par contre, le résultat est différent si un std::string est passé:
    - si c'est une référence qui est envoyer (variable non temporaire) alors une copie est faite [/QUOTE]Non, ca crashe (ou en tout cas, ca devrait): renvoyer une référence sur un objet temporaire revient à renvoyer une référence invalide, quelle que soit la manière dont tu envisages la chose
    - si c'est une variable temporaire (f3(std::string("abc"))) par exemple) alors ça dépend des optimisations du compilo. Par défaut il y a élision et la copie n'est pas faite. Donc un seul constructeur est appelé.
    Il y a bien élision de la copie, mais, comme tu crées explicitement la chaine de caractères, tu ne peux, quoi qu'il arrive, pas éviter l'appel au constructeur de std::string (et donc à l'allocation dynamique de la mémoire)
    À noté quand C++11 il y a le move semantic et le constructeur d'une rvalue (variable temporaire) d'un std::string ne fait pas d'allocation.
    Oh là... Attention:

    A partir du moment où l'argument est nommé, c'est une lvalue, même si c'est un objet temporaire.

    Pour profiter de la sémantique de mouvement, il faudrait utiliser explicitement std::move

    S'Il est vrai que le constructeur par déplacement n'est pas sensé faire d'allocation dynamique de la mémoire etant donné qu'il "vampirise" la rvalue qu'on lui fournit, on ne peut, quoi qu'il en soit, de toutes manières pas éviter la création de l'objet "vampirisé", et donc l'allocation dynamique qui va avec

    Nous en revenons donc au point de départ : au niveau de l'argument (transmis par valeur) en lui-même, il y aura soit une copie, soit une création et la sémantique de mouvement n'est pas applicable (parce que l'argument est nommé), sauf à y faire explicitement appel
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Merci

    J'aurais pas pensé que f2 génère une allocation, juste la création d'un string et copie du pointeur interne, mais pas la copie du contenu.

    Toujours bon à savoir.

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Merci

    J'aurais pas pensé que f2 génère une allocation, juste la création d'un string
    Ben, à partir de là, tout est dit
    et copie du pointeur interne, mais pas la copie du contenu.
    C'est pourtant "logique".

    Que ferais le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main(){
        char * ptr= new char[8];
        memcpy(ptr,"salut\0", 6);
        std::string str(ptr);
        memcpy(ptr,"hello\0", 6);
        // la ligne suivante affiche quoi? pourquoi? qu'est ce que cela afficherait 
        // s'il n'y avait pas copie du contenu?
        sdt::cout<<str<<std::endl;
        delete [] ptr;
        return 0;
    }
    s'il n'y avait pas copie du contenu, selon toi
    (le code est crade, mais il est légal, hein )
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre émérite

    Homme Profil pro
    Non disponible
    Inscrit en
    Décembre 2012
    Messages
    478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Non disponible

    Informations forums :
    Inscription : Décembre 2012
    Messages : 478
    Billets dans le blog
    1
    Par défaut
    Encore une fois, merci beaucoup Koala01 !
    Citation Envoyé par koala01 Voir le message
    Salut,
    A vrai dire, tu n'as pas vraiment à t'inquiéter de cela, car cela rentre vraiment dans l'optimisation prématurée, que tout le monde sait (ou du moins devrait savoir ) être la voie expresse vers tous les problèmes
    C'est en effet dans la signature d'un habitué du forum, et je le garde en tête. Toute ces explications me permettent néanmoins de mieux comprendre ce que je fait.

    Citation Envoyé par koala01 Voir le message
    1- Il y aura un "tableau de caractères" contenant "Salut tout le monde" (sans les guillemets ) qui prendra place dans une partie "read only" de ton exécutable (je crois qu'on appelle cette partie le "data segment"... à vérifier ).
    D'après wikipedia (...)
    "Data segment" serait une partie de la mémoire "read-write" de taille fixe réservée à l'application.
    La partie en "read-only" (pour la plupart des architectures) serait appelée "Code segment".
    Ils font aussi allusion à un certain "Rodata" dont j'ai plus de mal à trouver confirmation.

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par PilloBuenaGente Voir le message
    Encore une fois, merci beaucoup Koala01 !
    C'est en effet dans la signature d'un habitué du forum, et je le garde en tête. Toute ces explications me permettent néanmoins de mieux comprendre ce que je fait.
    Et c'est une citation que j'aime énormément, presque autant que celle de ma propre signature

    Mais bon, on n'a droit qu'à un espace limité pour la signature, alors...
    D'après wikipedia (...)
    "Data segment" serait une partie de la mémoire "read-write" de taille fixe réservée à l'application.
    La partie en "read-only" (pour la plupart des architectures) serait appelée "Code segment".
    Ils font aussi allusion à un certain "Rodata" dont j'ai plus de mal à trouver confirmation.
    Ben voilà, je me coucherai moins bête ce soir que je ne l'étais ce matin en me levant

    Merci d'avoir vérifié
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par PilloBuenaGente Voir le message
    Ils font aussi allusion à un certain "Rodata" dont j'ai plus de mal à trouver confirmation.
    intrigué, j'ai essayé d'en savoir plus sur la rodata.

    Le seul lien concluant que j'ai trouvé est ==>celui-ci<==.

    Les autres liens que j'ai trouvé sur le sujet sont tous reliés à l'éditeur de liens ld.

    Il semblerait donc que la section rodata soit une "invention" spécifique au monde libre (apparue avec la version 3-x de Gcc).

    Je ne serait pas étonné outre mesure qu'ils l'ont introduite afin de faciliter la mise en place du PIC (Position Independant Code), car quelques liens suivis indiquaient qu'il était possible d'affecter une valeur précise comme adresse de départ de cette section dans les scripts utilisés par ld

    Pour le reste, tout me porte à croire (peut être à tord ) qu'il ne s'agit en réalité que d'une séparation "artificielle" du segment code en deux parties distinctes... Mais je peux toujours me tromper
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Pour moi, ce serait plutôt une séparation du segment de données sur différentes pages, mais c'est parce que c'est ce que j'aurais fait.

    Sur x86, on veut que toutes les données, inscriptibles ou non (même si on ne peut pas les rendre non-inscriptible sur 8086) soient accessibles par DS, et non CS.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  12. #12
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Et sommes toutes, je serais bien tenté de te croire parce que la version 3 de Gcc nous ramène presque vingt ans en arrière (bon, allez, j'exagère un peu là : 12 ans en arrière seulement )

    Et comme l'assembleur et moi n'avons jamais été plus copains que ca...
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Occupation de la mémoire vive (RAM)
    Par GBAGO dans le forum AIX
    Réponses: 4
    Dernier message: 09/08/2011, 09h00
  2. Un logiciel qui suit l'occupation de la mémoire d'un processus donné
    Par Interruption13h dans le forum Windows XP
    Réponses: 5
    Dernier message: 02/04/2007, 03h33
  3. Réponses: 3
    Dernier message: 28/06/2005, 09h07
  4. différence entre varchar et text pour l'occupation mémoire
    Par champion dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 16/12/2004, 18h02
  5. Une TStringList occupe-t-elle beaucoup de mémoire ?
    Par Costello dans le forum Langage
    Réponses: 2
    Dernier message: 04/07/2004, 12h14

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