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 :

allocation mémoire statique ou dynamique, sur le tas ou la pile


Sujet :

C

  1. #1
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut allocation mémoire statique ou dynamique, sur le tas ou la pile
    Bonjour,

    Dans mes fonctions, j'ai constamment besoin d'allouer des zones mémoires de taille variable, au sens propre, c'est-à-dire qu'elle n'est pas prédéfinie mais connue uniquement lors de l'application.

    D'abord, est-ce que vous considérez les 2 équivalences
    alloc statique <==> sur la pile
    alloc dynamique <==> sur le tas
    comme correctes? Il me semble que c'est une erreur de conception. Si je comprends bien, historiquement il y avait bien un lien direct dans les deux cas, mais on peut attribuer cela à des limitations à la fois technologiques et du langage. Rien, d'alleurs, n'a jamais empêché de faire de l'allocation statique sur le tas. Et de nouveaux outils domme alloca permettent --à nouveau si je comprends bien-- de faire une allocation dynamique sur le pile. Ca vous semble tenir la route, comme point de vue?

    D'autre part, il y a une confusion totale à propos des termes statique / dynamique d'une part, et variable / constant de l'autre. Pour une raison que je ne comprends pas on utilise très souvent dynamique/statique (= qui peut/ne peut pas changer) pour dire en fait constant/variable (= qui a toujours ou non la même valeur, à chaque application) ; ou alors pour dire les deux à la fois (*).
    Dans le cas de l'allocation mémoire, ce n'est pour moi pas du tout la même chose de pouvoir allouer une taille variable (= qui dépend de directement de données variables, c'est à dire d'input), que de pouvoir allouer une taille dynamique (= qui peut changer en fonction de besoins actuels changeants). Qu'en pensez-vous?

    Passons à des interrogations un tout petit peu moins philosophico-programmatiques:

    Dans le cas où une zone mémoire doit être retournée à la fonction appelante, il me semble que l'allocation sur le tas via malloc et ses amis est nécessaire. Une allocation locale, sur la pile, serait perdue à la fin du bloc où elle a été allouée (==> segfault, si on de la chance). Je reformule ici des banalités sans doute triviales juste pour être sûr que je les pense bien et dans les bons termes. Merci de critiquer toute incorrection, ambiguité ou imprécision.

    Il arrive aussi plus rarement qu'une zone mémoire variable ait une utilité purement locale. Je viens ainsi d'écrire l'équivalent d'une caténation, mais sur des éléments qui ne sont pas des char* : il me faut donc un tableau intermédiaire, de taille variable, où je stocke leur expression textuelle. La constitution de ce tableau permet au passage de caculer la taille finale du texte et donc d'allouer celui-ci (sur le tas, malloc) exactement et d'un seul coup. Où mettre le tableau intermédiaire, et comment? Il est donc de taille variable et d'ailleurs sans limite prédéfinie. Je vois les possibilités suivantes:

    1. Sur la pile, en statique, surallloué avec une taille max dont l'usager est clairement prévenu. Mais quelle est la taille maxi? Comment sait-on jusqu'où la taille de la pile peut gonfler? (*)
    2. Utiliser alloca, donc une taille variable mais sur la pile. Même question au niveau des limites de la pile.
    3. Utiliser un tableau variable (VLA). Là, mon problème, c'est plutôt : où il est?
    Citation Envoyé par wikipedia [url
    http://en.wikipedia.org/wiki/Variable-length_array[/url]] One problem that may be hidden by a language's support for VLAs is that of the underlying memory allocation: in environments where there is a clear distinction between a heap and a stack, it may not be clear which, if any, of those will store the VLA.
    For example, the GNU C Compiler allocates memory for VLAs on the stack. If a VLA is too large, no error occurs immediately; instead, attempts to use the VLA may lead to segmentation faults later in the execution of the program.
    4. Sur le tas, via malloc.

    Je n'arrive pas bien à comprendre les avantages et inconvénients respectifs de chaque solution, sauf la première. Surtout, les avantages et inconvénients "différentiels", je veux dire les unes par rapport aux autres.

    Qu'en pensez-vous?

    Merci,
    Denis

    (*) Le cas typique étant le typage : quand on parle de typage statique, on veut généralement dire constant, c'est-à-dire qu'il est prédéfini lors de la conception (et explicitement dans le code ou par inférence de type) et donc constant lors de toute application. Parfois on veut aussi dire, el plus, statique, c'est-à-dire que le type ne change pas au cours d'une même application.
    (Un langage dit "dynamique" permet les deux : typage variable et dynamique. Mais le typage variable est en fait bien plus caractéristique de ces langages, et c'est ce qui leur coûte très cher en temps et espace.)
    En revanche, la terminologie du langage C pour les "variable-length arrays" (VLA) de C99 est tout-à-fait correcte : leur taille est "variable", mais pas "dynamic" --à ce que je sache.

    (**) Je considère que le tas peut gonfler à l'infini, et que le jour où, sur l'ordi d'un usager, on atteint la limite physique dispo à l'instant, c'est pas mon problème : on crashe, et basta!
    C'est différent pour la pile d'appels, j'ai l'impression qu'il est d ema responsabilité de bien la gérer, de pas y faire n'importe quoi.

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 293
    Points : 4 943
    Points
    4 943
    Billets dans le blog
    5
    Par défaut
    J'avoue ne pas me poser autant de questions sur le sujet .

    Pour moi, je résume ma façon de faire ainsi :
    • J'alloue dans le tas lorsque la portée des données doit être globale,
    • J'alloue dans le tas lorsque la quantité de mémoire nécessaire m'est inconnue. Ici vient un risque. L'oubli de désallouer une fois les données devenues inutiles,
    • J'alloue dans la pile lorsque je connais la taille maximale et que les données n'ont pas besoin de "sortir" de la fonction.

    Après, lorsque tu utilises une bibliothèque pour te facilité la vie, par exemple la glib pour mon cas, tu te retrouves à faire des allocations dans le tas pour des données qui pourraient être simplement allouées dans la pile.
    Par exemple la glib dispose d'un tas de fonctions bien pratiques pour manipuler des chaînes de caractères. Elles allouent pratiquement toutes dans le tas. Un "g_free();" est donc nécessaire. Attention à ce moment là à ne pas oublier de libérer tout ce petit monde avant de sortir.

  3. #3
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    J'avoue ne pas me poser autant de questions sur le sujet .
    Je comprends, je comprends... Tout le monde est pas aussi torturé d'la tête que moi (heureusement )

    Pour moi, je résume ma façon de faire ainsi :
    • J'alloue dans le tas lorsque la portée des données doit être globale,
    • J'alloue dans le tas lorsque la quantité de mémoire nécessaire m'est inconnue. Ici vient un risque. L'oubli de désallouer une fois les données devenues inutiles,
    • J'alloue dans la pile lorsque je connais la taille maximale et que les données n'ont pas besoin de "sortir" de la fonction.
    Mais comment tu fais pour savoir que ça passe, dans le cas 3?

    Après, lorsque tu utilises une bibliothèque pour te facilité la vie, par exemple la glib pour mon cas, tu te retrouves à faire des allocations dans le tas pour des données qui pourraient être simplement allouées dans la pile.
    Par exemple la glib dispose d'un tas de fonctions bien pratiques pour manipuler des chaînes de caractères. Elles allouent pratiquement toutes dans le tas. Un "g_free();" est donc nécessaire. Attention à ce moment là à ne pas oublier de libérer tout ce petit monde avant de sortir.
    Ben en fait, le genre de cas d'alloc purement locale me semble vivable, et aussi le plus "révisable" (je veux dire si tu revoies du code pour chercher des fuites, c'est assez facile pour un humain de répérer ce qui est local ou non --du moins je crois.
    Ce qui m'inquiète c'est les non-libérations d'allocs qui sont sorties de la fonction qui alloue, par les fonctions qui les utilisent. Le problème (pour éviter les fuites), c'est qu'il n'y a pas d'alloc sur place, par la fonction utilisatrice, donc pas de moyen de repérer ça systématiquement. D'ailleurs (comme dans ton cas de glib), on peut très bien ne pas savoir que c'est alloué sur le tas, non ?
    Je songe sérieusement à un recycleur (mon terme pour "ramasse-miettes" ).

    Denis

  4. #4
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Salut,

    comme le fait remarquer Gerald3d il y a les notions de portée (c'est lexical), de durée de vie (c'est le gestionnaire de mémoire), d'emplacements (c'est le hard) ...

    La portée peut-être
    • locale : cette variable n'existe que dans le bloc où elle est déclarée
    • globale : cette variable est visible de partout, la variable globale qui est déclarée en dehors de tout bloc. En c il y a une petite nuance : il y a les variables globale qui ne sont visibles que dans le module où on les déclare, ce sont celles qui sont "static" (rien à voir avec une allocation statique ou dynamique dans ce cas), et celle qui sont visibles partout où on les déclare "extern" il faut juste les définir une fois dans un module.


    La durée de vie :
    • auto : on ne trouve plus trop ce modificateur. C'est une varaible qui n'existe physiquement que le temps de sa portée. Typiquement toutes les variables locales, elle sont allouées automatiquement à l'entrée du bloc et détruites automatiquement en fin de bloc.
    • registre : ce modificateur est désuet aussi (voire même ignoré). C'est une variable pour laquelle aucune mémoire n'est jamais allouée car un registre sera utilisé pour la stocker durant sa portée.
    • dynamique : tu alloues dynamiquement, et la mémoire reste allouée tant qu'on ne la libère pas et est accessible de partout à condition d'en connaître l'adresse.


    L'emplacement. Il y a la pile, le tas, mais aussi les registres et les segments data du programme. Tous ces emplacements sont en mémoire (donc soit la RAM, le swap, les registres ...).La pile et le tas sont séparées conceptuellement car la pile est principalement utilisée pour les appels de fonctions et les variable locales (cela dépend aussi de l'ABI utilisée, l'ABI windows diffère de l'ABI linux) alors que le tas est de la mémoire à disposition pour usage général. La pile est généralement de taille limitée et le tas récupère le reste (mais c'est modifiable).

    Tu peux définir une variable locale de la durée de vie du programme (une variable locale static) ou une variable locale qui n'a aucun emplacement mémoire (-> dans un registre), tu peux créer une grosse structure qui sera un datasegment du programme ... tout cela regroupe plusieurs notions.

    Si tu veux définir une constante (non modifiable ...) il faut en passer par const (qui n'a rien à voir avec static, ni avec allocation dynamique/automatique).

    Un ramasse miette simplifie (souvent) la vie mais n'est pas une recette magique contre les fuites mémoires.

  5. #5
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 293
    Points : 4 943
    Points
    4 943
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par denispir Voir le message
    Je comprends, je comprends... Tout le monde est pas aussi torturé d'la tête que moi (heureusement )



    Mais comment tu fais pour savoir que ça passe, dans le cas 3?
    Pour répondre simplement : je n'en sais rien . Du moins je ne le fais pas si je sais que je risque d'approcher le Mo voir +.
    Le problème de la pile est que sa taille est très liée au système d'exploitation et bien sûr à la machine sur laquelle elle tourne. En cherchant sur internet on trouve la valeur de 16Mo sous Linux. Mais je n'ai pas trouvé la vérification de cette donnée.
    Il est aussi possible de forcer sa taille via les options de gcc. J'avoue ne jamais l'avoir fait.

    Citation Envoyé par denispir Voir le message
    ...
    D'ailleurs (comme dans ton cas de glib), on peut très bien ne pas savoir que c'est alloué sur le tas, non ?
    C'est le principe d'une documentation bien faite . J'utilise toujours la documentation de la glib à chaque fois que j'utilise une de ses fonctions. Elle indique si le résultat doit être explicitement libéré ou non.

    Citation Envoyé par denispir Voir le message
    Je songe sérieusement à un recycleur (mon terme pour "ramasse-miettes" ).

    Denis
    Pourquoi pas. Mais ca va t'obliger à écrire un nouvel malloc() et un nouveau free();. Sans parler d'un thread (il me semble) pour libérer les choses devenues inutiles. Les performances risques de s'écrouler, non?

  6. #6
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    Le problème de la pile est que sa taille est très liée au système d'exploitation et bien sûr à la machine sur laquelle elle tourne. En cherchant sur internet on trouve la valeur de 16Mo sous Linux. Mais je n'ai pas trouvé la vérification de cette donnée.
    Il est aussi possible de forcer sa taille via les options de gcc. J'avoue ne jamais l'avoir fait.
    Pour connaître la taille de la pile par défaut :
    Soit dans mon cas 8Mo

  7. #7
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 293
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 293
    Points : 4 943
    Points
    4 943
    Billets dans le blog
    5
    Par défaut
    J'ai trouvé ce post qui peut être aussi intéressant.

    Pour ce qui est de ulimit -s => même chose chez moi... 8Mo.

  8. #8
    Membre habitué
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par kwariz Voir le message
    Pour connaître la taille de la pile par défaut :
    Soit dans mon cas 8Mo
    Chez moi aussi.
    Denis

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 573
    Points
    41 573
    Par défaut
    La pile sous Windows ne fait qu'un seul Mo par défaut.

    Le problème de "statique" en fait, c'est que c'est un abus de langage quand on parle de la pile comme "statique". Le terme exact serait "automatique", tandis que "statique" serait à réserver aux variables static et/ou globales.

    Personnellement, je trouve que l'usage de la pile est du type "si vous voulez savoir la taille maximale, vous allouez trop dessus". Hormis code critique en performance, j'alloue rarement plus gros que quelques entiers et un buffer de 80 caractères (ou 260 pour certains cas).
    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.

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

Discussions similaires

  1. [wxWidgets] Allocation statique et dynamique
    Par three minute hero dans le forum wxWidgets
    Réponses: 7
    Dernier message: 25/06/2007, 23h19
  2. Petite question rapide sur allocation mémoire
    Par adn013 dans le forum Langage
    Réponses: 5
    Dernier message: 11/06/2007, 16h10
  3. Réponses: 28
    Dernier message: 27/05/2007, 15h16
  4. Mémoire dynamique / Mémoire statique
    Par _LVEB_ dans le forum C++
    Réponses: 8
    Dernier message: 02/04/2007, 23h33
  5. Allocation mémoire dynamique
    Par ITISAR dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 21/01/2005, 09h59

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