Pile vs tas : les différences expliquées

Un programme en cours d'exécution utilise deux régions principales de mémoire pour ses données. La pile (stack) contient les cadres d'appel de fonction : variables locales, arguments et adresses de retour. Elle est gérée automatiquement et très rapide, mais petite et liée à la durée de vie de chaque appel de fonction. Le tas (heap) contient la mémoire que le programme demande explicitement, par exemple avec malloc ou new, et qui existe jusqu'à sa libération. Le tas est souple et vaste mais plus lent, et c'est là que surviennent les fuites et la fragmentation.

CritèrePile (stack)Tas (heap)
UsageCadres d'appel de fonction : variables locales, arguments, adresses de retourDonnées allouées dynamiquement qui doivent survivre à une fonction ou dont la taille n'est pas connue à l'avance
AllocationAutomatique : le pointeur de pile se déplace à chaque appel et à chaque retourExplicite : malloc et free, new et delete, ou un garbage collector
VitesseTrès rapide : il suffit d'ajuster un pointeurPlus lente : l'allocateur doit trouver un bloc libre et tenir des registres
Durée de vieJusqu'au retour de la fonctionJusqu'à la libération de la mémoire (ou son ramassage par le garbage collector)
TailleLimitée (typiquement quelques mégaoctets par thread)Limitée uniquement par la mémoire disponible
DispositionCroît généralement vers le bas depuis les adresses hautesCroît généralement vers le haut depuis des adresses plus basses : les deux croissent l'une vers l'autre
FragmentationAucunePossible : des allocations et libérations répétées peuvent laisser des trous inutilisables
ThreadsChaque thread possède sa propre pile privéePartagé par tous les threads : l'allocateur doit donc être thread-safe
Erreurs typiquesDébordement de pile dû à une récursion profonde ou à de grands tableaux locauxFuites de mémoire, use after free, double libération et épuisement de la mémoire

Les valeurs indiquées sont des ordres de grandeur typiques et varient selon la génération de procédé et le produit.

Quand choisir l'un ou l'autre ?

Pile
Pour des données petites et de courte durée dont la taille est connue à la compilation : les variables locales ordinaires.
Tas
Pour les données volumineuses, les données dont la taille change à l'exécution, et les données qui doivent survivre à la fonction qui les a créées.

Questions fréquentes

Pourquoi l'allocation sur la pile est-elle plus rapide que sur le tas ?

L'allocation sur la pile ne fait que déplacer le pointeur de pile, tandis que l'allocation sur le tas doit trouver un bloc libre et mettre à jour les registres de l'allocateur.

Qu'est-ce qui provoque un débordement de pile ?

L'utilisation excessive de la pile, typiquement par une récursion profonde ou infinie ou par de très grands tableaux locaux, qui dépasse la taille limite de la pile et fait planter le programme.

Qu'est-ce qu'une fuite de mémoire ?

De la mémoire du tas allouée mais jamais libérée, qui ne peut donc pas être réutilisée. Des fuites répétées font consommer au programme de plus en plus de mémoire.

Les threads partagent-ils la pile ?

Non. Chaque thread possède sa propre pile, tandis que tous les threads partagent le tas.

Vérifier vos connaissances

Quel est l'avantage de l'agencement qui fait croître le tas et la pile d'un processus en sens opposés, avec un vaste espace libre entre eux ?

  1. AL'espace libre peut être partagé de façon souple entre les deux, sans savoir à l'avance combien chacun utilisera
  2. BLe tas et la pile pouvant utiliser simultanément les mêmes adresses, la mémoire est doublée
  3. CLa pile ne peut plus jamais déborder
Afficher la réponse et l'explication

Réponse : A. L'espace libre peut être partagé de façon souple entre les deux, sans savoir à l'avance combien chacun utilisera

Le tas croissant vers les adresses hautes et la pile vers les basses, l'espace libre intermédiaire peut servir aussi bien aux programmes qui utilisent beaucoup le tas qu'à ceux qui utilisent beaucoup la pile. Avec une taille fixe attribuée à chacun, l'un pourrait déborder alors que l'autre a de la place. Cependant, une limite est souvent fixée pour la pile, et une récursion trop profonde la dépasse et provoque un débordement de pile.

De quelle zone du processus provient généralement la mémoire allouée par malloc en C ?

  1. ALa section .text
  2. BLe tas
  3. CLa section .rodata
Afficher la réponse et l'explication

Réponse : B. Le tas

Le tas est la zone où l'on alloue pendant l'exécution la quantité de mémoire nécessaire et où on la restitue par free lorsqu'elle n'est plus utile. Sa particularité est que la taille et la durée de vie des allocations peuvent être décidées à l'exécution. malloc gère lui-même l'espace libre et, lorsqu'il manque, demande à l'OS d'étendre la zone (appels système brk ou mmap sous Linux). Oublier free laisse subsister de la mémoire inutilisée : c'est une fuite de mémoire.

Quel est l'agencement mémoire correct d'un processus typique sous Linux notamment, des adresses basses aux adresses hautes ?

  1. ATexte → données → BSS → tas → (espace libre) → pile
  2. BPile → texte → tas → données → BSS
  3. CTas → pile → BSS → données → texte
Afficher la réponse et l'explication

Réponse : A. Texte → données → BSS → tas → (espace libre) → pile

Dans l'agencement typique, on trouve des adresses basses vers les hautes le texte (langage machine), les données initialisées et le BSS initialisé à 0, au-dessus desquels le tas croît vers les adresses hautes. La pile croît des adresses hautes vers les basses, et le vaste espace libre entre les deux accueille les bibliothèques partagées et les zones mmap. Les adresses réelles sont décalées à chaque exécution par l'ASLR pour des raisons de sécurité.

  1. Lorsqu'une récursion trop profonde dépasse la limite de la pile, que se passe-t-il généralement sous Linux notamment ?
  2. À force de répéter malloc et free, il peut devenir impossible d'allouer un grand bloc d'un seul tenant alors que la mémoire libre totale est suffisante. Comment appelle-t-on ce phénomène ?
  3. En RISC-V, que se passe-t-il si l'on oublie de sauvegarder ra sur la pile en écrivant une fonction récursive qui s'appelle elle-même ?

Questions d'entraînement sur Éditeurs de liens, chargeurs et exécutables

Termes clés expliqués

Cadre de pile (stack frame)
Zone allouée sur la pile à chaque appel de fonction. Elle contient l'adresse de retour, les registres sauvegardés, les variables locales, etc., et est libérée au retour de la fonction.
Pointeur de pile
Registre pointant sur l'adresse du sommet actuel de la pile. En RISC-V, c'est sp (x2). Dans de nombreuses ISA, la pile croît vers les adresses basses.
Tas (heap)
Zone mémoire où, pendant l'exécution, on alloue la taille nécessaire avec malloc, etc., et qu'on libère avec free. Des allocations et libérations répétées peuvent provoquer une fragmentation.

Comparatifs associés