Quoi et où sont la stack et le tas?

Les manuels de langage de programmation expliquent que les types de valeur sont créés sur la stack et que les types de référence sont créés sur le tas , sans expliquer ce que sont ces deux éléments. Je n’ai pas lu d’explication claire à ce sujet. Je comprends ce qu’est une stack . Mais,

  • où et quels sont-ils (physiquement dans la mémoire d’un vrai ordinateur)?
  • Dans quelle mesure sont-ils contrôlés par le système d’exploitation ou le langage d’exécution?
  • Quelle est leur scope?
  • Qu’est ce qui détermine la taille de chacun d’eux?
  • Qu’est-ce qui rend un plus rapide?

La stack est la mémoire mise de côté comme espace de travail pour un thread d’exécution. Lorsqu’une fonction est appelée, un bloc est réservé en haut de la stack pour les variables locales et certaines données comptables. Lorsque cette fonction retourne, le bloc devient inutilisé et peut être utilisé la prochaine fois qu’une fonction est appelée. La stack est toujours réservée dans un ordre LIFO (dernier entré, premier sorti); le bloc le plus récemment réservé est toujours le prochain bloc à libérer. Cela rend très simple de garder une trace de la stack; libérer un bloc de la stack n’est rien d’autre que l’ajustement d’un pointeur.

Le tas est une mémoire réservée à l’allocation dynamic. Contrairement à la stack, il n’y a pas de modèle appliqué à l’allocation et à la désallocation des blocs du segment de mémoire; vous pouvez allouer un bloc à tout moment et le libérer à tout moment. Cela rend beaucoup plus complexe le suivi des parties du tas allouées ou libres à un moment donné; Il existe de nombreux allocateurs de segments personnalisés disponibles pour optimiser les performances du tas pour différents modèles d’utilisation.

Chaque thread obtient une stack, alors qu’il n’y a généralement qu’un seul segment de mémoire pour l’application (bien qu’il ne soit pas rare d’avoir plusieurs tas pour différents types d’allocation).

Pour répondre directement à vos questions:

Dans quelle mesure sont-ils contrôlés par le système d’exploitation ou le langage d’exécution?

Le système d’exploitation alloue la stack pour chaque thread de niveau système lors de la création du thread. En règle générale, le système d’exploitation est appelé par le langage d’exécution pour allouer le tas pour l’application.

Quelle est leur scope?

La stack est attachée à un thread, donc lorsque le thread quitte la stack est récupéré. Le tas est généralement alloué au démarrage de l’application par le moteur d’exécution et est récupéré à la fermeture de l’application (techniquement en cours de traitement).

Qu’est ce qui détermine la taille de chacun d’eux?

La taille de la stack est définie lors de la création d’un thread. La taille du tas est définie au démarrage de l’application, mais peut augmenter à mesure que l’espace est requirejs (l’allocateur demande davantage de mémoire au système d’exploitation).

Qu’est-ce qui rend un plus rapide?

La stack est plus rapide car le modèle d’access rend sortingvial d’allouer et de désallouer de la mémoire (un pointeur / entier est simplement incrémenté ou décrémenté), alors que le tas a une comptabilité beaucoup plus complexe impliquée dans une allocation ou une désallocation. De plus, chaque octet de la stack a tendance à être réutilisé très fréquemment, ce qui signifie qu’il a tendance à être associé au cache du processeur, ce qui le rend très rapide. Un autre problème de performance du segment de mémoire est que le segment de mémoire, en général une ressource globale, doit être multi-threading, c’est-à-dire que chaque allocation et désallocation doit être synchronisée avec tous les autres access au segment.

Une démonstration claire:
Source de l’image: vikashazrati.wordpress.com

Emstackr:

  • Stocké dans la RAM de l’ordinateur comme le tas.
  • Les variables créées sur la stack seront hors de scope et seront automatiquement désallouées.
  • Beaucoup plus rapide à allouer par rapport aux variables sur le tas.
  • Implémenté avec une structure de données de stack réelle.
  • Stocke les données locales, les adresses de retour, utilisées pour le passage des parameters.
  • Peut avoir un dépassement de stack lorsque trop de stack est utilisée (principalement à cause d’une récursivité infinie ou trop profonde, d’allocations très importantes).
  • Les données créées sur la stack peuvent être utilisées sans pointeurs.
  • Vous utiliseriez la stack si vous savez exactement quelle quantité de données vous devez allouer avant la compilation et si elle n’est pas trop grande.
  • A généralement une taille maximale déjà déterminée au démarrage de votre programme.

Tas:

  • Stocké dans la RAM de l’ordinateur comme la stack.
  • En C ++, les variables sur le tas doivent être détruites manuellement et ne jamais tomber hors de la scope. Les données sont libérées avec delete , delete[] ou free .
  • Plus lent à allouer par rapport aux variables de la stack.
  • Utilisé à la demande pour allouer un bloc de données à utiliser par le programme.
  • Peut avoir une fragmentation quand il y a beaucoup d’allocations et de désallocations.
  • En C ++ ou C, les données créées sur le tas seront désignées par des pointeurs et allouées avec new ou malloc respectivement.
  • Peut avoir des échecs d’allocation si un tampon trop grand est demandé.
  • Vous utiliseriez le tas si vous ne savez pas exactement combien de données vous aurez besoin au moment de l’exécution ou si vous avez besoin d’allouer beaucoup de données.
  • Responsable des memory leaks.

Exemple:

 int foo() { char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack). bool b = true; // Allocated on the stack. if(b) { //Create 500 bytes on the stack char buffer[500]; //Create 500 bytes on the heap pBuffer = new char[500]; }//<-- buffer is deallocated here, pBuffer is not }//<--- oops there's a memory leak, I should have called delete[] pBuffer; 

Le point le plus important est que le tas et la stack sont des termes génériques permettant d’atsortingbuer de la mémoire. Ils peuvent être mis en œuvre de différentes manières et les termes s’appliquent aux concepts de base.

  • Dans une stack d’objects, les objects sont superposés dans l’ordre où ils ont été placés, et vous ne pouvez supprimer que le premier (sans renverser le tout).

    Pile comme une pile de papiers

    La simplicité d’une stack est que vous n’avez pas besoin de maintenir une table contenant un enregistrement de chaque section de la mémoire allouée; Les seules informations d’état dont vous avez besoin sont un seul pointeur vers la fin de la stack. Pour allouer et désallouer, il vous suffit d’incrémenter et de décrémenter ce pointeur unique. Remarque: une stack peut parfois être implémentée pour démarrer en haut d’une section de mémoire et s’étendre vers le bas plutôt que vers le haut.

  • Dans un tas, il n’y a pas d’ordre particulier à la façon dont les articles sont placés. Vous pouvez atteindre et supprimer des éléments dans n’importe quel ordre car il n’y a pas d’élément ‘top’ clair.

    Tas comme un tas de réglisse

    L’allocation de segment de mémoire nécessite de conserver un enregistrement complet de la mémoire allouée et de ce qui ne l’est pas, ainsi que des tâches de maintenance afin de réduire la fragmentation, de trouver des segments de mémoire contigus suffisamment grands pour la taille requirejse, etc. La mémoire peut être libérée à tout moment en laissant de l’espace libre. Parfois, un allocateur de mémoire exécute des tâches de maintenance telles que la défragmentation de la mémoire en déplaçant la mémoire allouée ou la récupération de la mémoire – en identifiant à l’exécution lorsque la mémoire n’est plus étendue et en la libérant.

Ces images devraient décrire assez bien les deux manières d’allouer et de libérer de la mémoire dans une stack et un tas. Miam!

  • Dans quelle mesure sont-ils contrôlés par le système d’exploitation ou le langage d’exécution?

    Comme mentionné, le tas et la stack sont des termes généraux et peuvent être implémentés de plusieurs manières. Les programmes informatiques ont généralement une stack appelée stack d’ appels qui stocke des informations pertinentes pour la fonction en cours, par exemple un pointeur vers la fonction à partir de laquelle elle a été appelée, et toutes les variables locales. Étant donné que les fonctions appellent d’autres fonctions, puis reviennent, la stack se développe et se réduit pour contenir les informations des fonctions situées plus bas dans la stack d’appels. Un programme n’a pas vraiment de contrôle d’exécution à ce sujet; il est déterminé par le langage de programmation, le système d’exploitation et même l’architecture du système.

    Un tas est un terme général utilisé pour toute mémoire allouée de manière dynamic et aléatoire; c’est-à-dire en panne. La mémoire est généralement allouée par le système d’exploitation, l’application appelant les fonctions de l’API pour effectuer cette allocation. La gestion de la mémoire allouée dynamicment, qui est généralement gérée par le système d’exploitation, nécessite une surcharge importante.

  • Quelle est leur scope?

    La stack d’appels est un concept tellement bas qu’il ne concerne pas la «scope» au sens de la programmation. Si vous démontez du code, vous verrez des références de style de pointeur relatives à des parties de la stack, mais en ce qui concerne un langage de niveau supérieur, le langage impose ses propres règles de scope. Un aspect important d’une stack, cependant, est qu’une fois qu’une fonction retourne, tout élément local de cette fonction est immédiatement libéré de la stack. Cela fonctionne comme vous le souhaitiez, compte tenu du fonctionnement de vos langages de programmation. En tas, c’est aussi difficile à définir. La scope est celle qui est exposée par le système d’exploitation, mais votre langage de programmation ajoute probablement ses règles sur ce qu’est une «étendue» dans votre application. L’architecture du processeur et le système d’exploitation utilisent l’adressage virtuel, que le processeur traduit en adresses physiques et qu’il y a des défauts de page, etc. Ils enregistrent les pages appartenant à quelles applications. Cependant, vous n’avez jamais vraiment besoin de vous inquiéter, car vous utilisez simplement la méthode utilisée par votre langage de programmation pour allouer et libérer de la mémoire, et vérifier les erreurs (si l’atsortingbution / la libération échoue pour une raison quelconque).

  • Qu’est ce qui détermine la taille de chacun d’eux?

    Encore une fois, cela dépend du langage, du compilateur, du système d’exploitation et de l’architecture. Une stack est généralement pré-allouée car, par définition, elle doit être contiguë (plus d’informations dans le dernier paragraphe). Le compilateur de langue ou le système d’exploitation détermine sa taille. Vous ne stockez pas d’énormes blocs de données sur la stack, de sorte qu’elle sera suffisamment grande pour ne jamais être entièrement utilisée, sauf en cas de récursion sans fin indésirable (d’où un «dépassement de stack») ou d’autres décisions de programmation inhabituelles.

    Un tas est un terme général pour tout ce qui peut être alloué dynamicment. Selon la façon dont vous le regardez, la taille change constamment. Dans les processeurs et les systèmes d’exploitation modernes, la façon dont cela fonctionne est très abstraite de toute façon, vous n’avez donc pas besoin de vous soucier de son fonctionnement, sauf que (dans les langues où cela vous permet) vous ne devez pas utiliser de mémoire. vous n’avez pas encore alloué ou mémoire que vous avez libéré.

  • Qu’est-ce qui rend un plus rapide?

    La stack est plus rapide car toute la mémoire libre est toujours contiguë. Aucune liste de tous les segments de mémoire libre ne doit être conservée, juste un seul pointeur vers le sumt actuel de la stack. Les compilateurs stockent généralement ce pointeur dans un registre spécial et rapide à cet effet. Qui plus est, les opérations ultérieures sur une stack sont généralement concentrées dans des zones de mémoire très proches, ce qui, à un niveau très bas, peut être optimisé par les caches de processeur.

(J’ai déplacé cette réponse d’une autre question qui était plus ou moins dupe de celle-ci.)

La réponse à votre question est spécifique à la mise en œuvre et peut varier selon les compilateurs et les architectures de processeur. Cependant, voici une explication simplifiée.

  • La stack et le tas sont tous deux des zones de mémoire allouées à partir du système d’exploitation sous-jacent (souvent de la mémoire virtuelle mappée à la mémoire physique à la demande).
  • Dans un environnement multithread, chaque thread aura sa propre stack complètement indépendante mais partagera le tas. L’access simultané doit être contrôlé sur le tas et n’est pas possible sur la stack.

Le tas

  • Le tas contient une liste liée de blocs utilisés et libres. Les nouvelles allocations sur le tas (par new ou malloc ) sont satisfaites en créant un bloc approprié à partir de l’un des blocs libres. Cela nécessite la mise à jour de la liste des blocs sur le tas. Ces méta-informations sur les blocs du tas sont également stockées sur le tas souvent dans une petite zone juste devant chaque bloc.
  • À mesure que le tas grandit, de nouveaux blocs sont souvent atsortingbués à partir d’adresses plus faibles vers des adresses plus élevées. Ainsi, vous pouvez considérer le tas comme un tas de blocs de mémoire dont la taille augmente à mesure que la mémoire est allouée. Si le tas est trop petit pour une allocation, la taille peut souvent être augmentée en acquérant davantage de mémoire à partir du système d’exploitation sous-jacent.
  • Allouer et libérer de nombreux petits blocs peut laisser le tas dans un état où il y a beaucoup de petits blocs libres intercalés entre les blocs utilisés. Une demande d’allocation d’un grand bloc peut échouer car aucun des blocs libres n’est suffisamment grand pour satisfaire la demande d’allocation même si la taille combinée des blocs libres est suffisamment grande. Cela s’appelle la fragmentation du tas .
  • Lorsqu’un bloc utilisé qui est adjacent à un bloc libre est libéré, le nouveau bloc libre peut être fusionné avec le bloc libre adjacent pour créer un bloc libre plus grand réduisant efficacement la fragmentation du tas.

Le tas

La stack

  • La stack fonctionne souvent en tandem avec un registre spécial sur le processeur nommé le pointeur de stack . Initialement, le pointeur de la stack pointe vers le haut de la stack (l’adresse la plus élevée de la stack).
  • Le CPU a des instructions spéciales pour pousser les valeurs sur la stack et les extraire de la stack. Chaque push stocke la valeur à l’emplacement actuel du pointeur de stack et diminue le pointeur de stack. Un pop récupère la valeur indiquée par le pointeur de la stack, puis augmente le pointeur de la stack (ne perdez pas de vue le fait que l’ ajout d’ une valeur à la stack diminue le pointeur de la stack et que sa suppression augmente) . le fond). Les valeurs stockées et récupérées sont les valeurs des registres CPU.
  • Lorsqu’une fonction est appelée, la CPU utilise des instructions spéciales qui poussent le pointeur d’instruction en cours, c’est-à-dire l’adresse du code s’exécutant sur la stack. La CPU passe alors à la fonction en réglant le pointeur d’instruction sur l’adresse de la fonction appelée. Plus tard, lorsque la fonction retourne, l’ancien pointeur d’instruction est sorti de la stack et l’exécution reprend au code juste après l’appel à la fonction.
  • Lorsqu’une fonction est entrée, le pointeur de la stack est diminué pour allouer plus d’espace sur la stack pour les variables locales (automatiques). Si la fonction a une variable 32 bits locale, quatre octets sont mis de côté sur la stack. Lorsque la fonction retourne, le pointeur de la stack est déplacé pour libérer la zone allouée.
  • Si une fonction a des parameters, ceux-ci sont poussés dans la stack avant l’appel à la fonction. Le code dans la fonction est alors capable de naviguer dans la stack à partir du pointeur de stack actuel pour localiser ces valeurs.
  • Les appels de fonction d’imbrication fonctionnent comme un charme. Chaque nouvel appel allouera des parameters de fonction, l’adresse de retour et l’espace pour les variables locales. Ces enregistrements d’activation peuvent être empilés pour les appels nesteds et se dérouleront correctement lorsque les fonctions reviendront.
  • Comme la stack est un bloc de mémoire limité, vous pouvez provoquer un débordement de stack en appelant trop de fonctions nestedes et / ou en allouant trop d’espace aux variables locales. Souvent, la zone mémoire utilisée pour la stack est configurée de telle manière que l’écriture sous le bas (l’adresse la plus basse) de la stack déclenche une interruption ou une exception dans la CPU. Cette condition exceptionnelle peut alors être interceptée par le moteur d’exécution et convertie en une sorte d’exception de dépassement de capacité de la stack.

La pile

Une fonction peut-elle être allouée sur le tas plutôt que sur une stack?

Non, les enregistrements d’activation des fonctions (variables locales ou automatiques) sont alloués sur la stack, non seulement pour stocker ces variables, mais également pour suivre les appels de fonctions nesteds.

Le mode de gestion du tas dépend vraiment de l’environnement d’exécution. C utilise malloc et C ++ utilise new , mais de nombreux autres langages ont un nettoyage des ordures.

Cependant, la stack est une fonctionnalité de bas niveau étroitement liée à l’architecture du processeur. Augmenter le tas quand il n’y a pas assez d’espace n’est pas trop difficile, car il peut être implémenté dans l’appel de bibliothèque qui gère le tas. Cependant, il est souvent impossible de faire pousser la stack car le débordement de la stack est découvert uniquement lorsqu’il est trop tard; et la fermeture du thread d’exécution est la seule option viable.

Dans le code C # suivant

 public void Method1() { int i = 4; int y = 2; class1 cls1 = new class1(); } 

Voici comment la mémoire est gérée

Image de variables sur la pile

Local Variables qui ne durent que tant que l’invocation de la fonction a lieu dans la stack. Le tas est utilisé pour les variables dont nous ne connaissons pas la durée de vie initiale, mais nous nous attendons à ce qu’elles durent un certain temps. Dans la plupart des langues, il est essentiel que nous sachions au moment de la compilation quelle est la taille d’une variable si nous voulons la stocker sur la stack.

Les objects (dont la taille varie lorsque nous les mettons à jour) vont sur le tas car nous ne soaps pas au moment de la création combien de temps ils dureront. Dans de nombreuses langues, le tas est récupéré pour trouver des objects (tels que l’object cls1) qui n’ont plus de références.

En Java, la plupart des objects vont directement dans le tas. Dans des langages comme C / C ++, les structures et les classes peuvent souvent restr sur la stack lorsque vous ne traitez pas de pointeurs.

Plus d’informations peuvent être trouvées ici:

La différence entre l’allocation de stack et la mémoire de tas «timmurphy.org

et ici:

Créer des objects sur la stack et le tas

Cet article est la source de l’image ci-dessus: Six concepts .NET importants: Stack, tas, types de valeur, types de référence, boxe et unboxing – CodeProject

mais sachez qu’il peut contenir des inexactitudes.

The Stack Lorsque vous appelez une fonction, les arguments associés à cette fonction, plus un autre surcoût, sont placés sur la stack. Certaines informations (par exemple, où aller en retour) y sont également stockées. Lorsque vous déclarez une variable dans votre fonction, cette variable est également allouée sur la stack.

La désallocation de la stack est assez simple car vous désallouez toujours dans l’ordre inverse dans lequel vous allouez. Des éléments de stack sont ajoutés lorsque vous entrez des fonctions, les données correspondantes sont supprimées lorsque vous les quittez. Cela signifie que vous avez tendance à restr dans une petite région de la stack, à moins d’appeler beaucoup de fonctions appelant beaucoup d’autres fonctions (ou de créer une solution récursive).

Le tas Le tas est un nom générique pour l’endroit où vous placez les données que vous créez à la volée. Si vous ne savez pas combien de vaisseaux spatiaux votre programme va créer, vous utiliserez probablement le nouvel opérateur (ou malloc ou équivalent) pour créer chaque vaisseau spatial. Cette allocation va durer un moment, il est donc probable que nous allons libérer les choses dans un ordre différent de celui que nous avons créé.

Ainsi, le tas est beaucoup plus complexe, car il se trouve que les régions de la mémoire sont inutilisées et entrelacées avec des morceaux – la mémoire est fragmentée. Trouver de la mémoire gratuite de la taille dont vous avez besoin est un problème difficile. C’est pourquoi le tas doit être évité (même s’il est encore souvent utilisé).

Implémentation L’ implémentation à la fois de la stack et du tas revient généralement à l’exécution / au système d’exploitation. Souvent, les jeux et autres applications critiques sur le plan des performances créent leurs propres solutions de mémoire qui capturent une grande partie de la mémoire du tas, puis les dissortingbuent en interne pour éviter de dépendre de l’OS pour la mémoire.

Ceci n’est pratique que si votre utilisation de la mémoire est très différente de la norme – c’est-à-dire pour les jeux où vous chargez un niveau en une seule opération et qui peut vous emmener dans une autre opération énorme.

Emplacement physique en mémoire Ceci est moins pertinent que vous ne le pensez en raison d’une technologie appelée mémoire virtuelle qui fait croire à votre programme que vous avez access à une certaine adresse où les données physiques se trouvent ailleurs (même sur le disque dur!). Les adresses que vous obtenez pour la stack sont en ordre croissant au fur et à mesure que votre arbre d’appel devient plus profond. Les adresses du tas ne sont pas prévisibles (c.-à-d. Spécifiques à l’implémentation) et franchement pas importantes.

Pour clarifier, cette réponse a des informations incorrectes ( thomas a corrigé sa réponse après les commentaires, cool :)). D’autres réponses évitent simplement d’expliquer ce que signifie une allocation statique. Je vais donc expliquer les trois principales formes d’allocation et leur relation habituelle avec le segment de mémoire, la stack et le segment de données ci-dessous. Je vais aussi montrer quelques exemples en C / C ++ et en Python pour aider les gens à comprendre.

Les variables “statiques” (AKA allouées statiquement) ne sont pas allouées sur la stack. Ne le supposez pas – beaucoup de gens le font uniquement parce que “statique” ressemble beaucoup à “stack”. Ils existent réellement dans ni la stack ni le tas. Les font partie de ce qu’on appelle le segment de données .

Cependant, il est généralement préférable de considérer ” scope ” et ” lifetime ” plutôt que “stack” et “heap”.

Scope fait référence à quelles parties du code peuvent accéder à une variable. En général, nous pensons à la scope locale (accessible uniquement par la fonction actuelle) par rapport à la scope globale (accessible partout), bien que la scope puisse devenir beaucoup plus complexe.

La durée de vie se réfère au moment où une variable est allouée et désallouée pendant l’exécution du programme. Habituellement, nous pensons à l’allocation statique (la variable persistera pendant toute la durée du programme, ce qui la rend utile pour stocker les mêmes informations sur plusieurs appels de fonction) par rapport à l’allocation automatique (la variable ne persiste stocker des informations qui ne sont utilisées que pendant votre fonction et peuvent être supprimées une fois que vous avez terminé) par rapport à l’allocation dynamic (variables dont la durée est définie à l’exécution, au lieu de la compilation comme statique ou automatique).

Although most comstackrs and interpreters implement this behavior similarly in terms of using stacks, heaps, etc, a comstackr may sometimes break these conventions if it wants as long as behavior is correct. For instance, due to optimization a local variable may only exist in a register or be removed entirely, even though most local variables exist in the stack. As has been pointed out in a few comments, you are free to implement a comstackr that doesn’t even use a stack or a heap, but instead some other storage mechanisms (rarely done, since stacks and heaps are great for this).

I will provide some simple annotated C code to illustrate all of this. The best way to learn is to run a program under a debugger and watch the behavior. If you prefer to read python, skip to the end of the answer 🙂

 // Statically allocated in the data segment when the program/DLL is first loaded // Deallocated when the program/DLL exits // scope - can be accessed from anywhere in the code int someGlobalVariable; // Statically allocated in the data segment when the program is first loaded // Deallocated when the program/DLL exits // scope - can be accessed from anywhere in this particular code file static int someStaticVariable; // "someArgument" is allocated on the stack each time MyFunction is called // "someArgument" is deallocated when MyFunction returns // scope - can be accessed only within MyFunction() void MyFunction(int someArgument) { // Statically allocated in the data segment when the program is first loaded // Deallocated when the program/DLL exits // scope - can be accessed only within MyFunction() static int someLocalStaticVariable; // Allocated on the stack each time MyFunction is called // Deallocated when MyFunction returns // scope - can be accessed only within MyFunction() int someLocalVariable; // A *pointer* is allocated on the stack each time MyFunction is called // This pointer is deallocated when MyFunction returns // scope - the pointer can be accessed only within MyFunction() int* someDynamicVariable; // This line causes space for an integer to be allocated in the heap // when this line is executed. Note this is not at the beginning of // the call to MyFunction(), like the automatic variables // scope - only code within MyFunction() can access this space // *through this particular variable*. // However, if you pass the address somewhere else, that code // can access it too someDynamicVariable = new int; // This line deallocates the space for the integer in the heap. // If we did not write it, the memory would be "leaked". // Note a fundamental difference between the stack and heap // the heap must be managed. The stack is managed for us. delete someDynamicVariable; // In other cases, instead of deallocating this heap space you // might store the address somewhere more permanent to use later. // Some languages even take care of deallocation for you... but // always it needs to be taken care of at runtime by some mechanism. // When the function returns, someArgument, someLocalVariable // and the pointer someDynamicVariable are deallocated. // The space pointed to by someDynamicVariable was already // deallocated prior to returning. return; } // Note that someGlobalVariable, someStaticVariable and // someLocalStaticVariable continue to exist, and are not // deallocated until the program exits. 

A particularly poignant example of why it’s important to distinguish between lifetime and scope is that a variable can have local scope but static lifetime – for instance, “someLocalStaticVariable” in the code sample above. Such variables can make our common but informal naming habits very confusing. For instance when we say ” local ” we usually mean ” locally scoped automatically allocated variable ” and when we say global we usually mean ” globally scoped statically allocated variable “. Unfortunately when it comes to things like ” file scoped statically allocated variables ” many people just say… ” huh??? “.

Some of the syntax choices in C/C++ exacerbate this problem – for instance many people think global variables are not “static” because of the syntax shown below.

 int var1; // Has global scope and static allocation static int var2; // Has file scope and static allocation int main() {return 0;} 

Note that putting the keyword “static” in the declaration above prevents var2 from having global scope. Nevertheless, the global var1 has static allocation. This is not intuitive! For this reason, I try to never use the word “static” when describing scope, and instead say something like “file” or “file limited” scope. However many people use the phrase “static” or “static scope” to describe a variable that can only be accessed from one code file. In the context of lifetime, “static” always means the variable is allocated at program start and deallocated when program exits.

Some people think of these concepts as C/C++ specific. Ils ne sont pas. For instance, the Python sample below illustrates all three types of allocation (there are some subtle differences possible in interpreted languages that I won’t get into here).

 from datetime import datetime class Animal: _FavoriteFood = 'Undefined' # _FavoriteFood is statically allocated def PetAnimal(self): curTime = datetime.time(datetime.now()) # curTime is automatically allocatedion print("Thank you for petting me. But it's " + str(curTime) + ", you should feed me. My favorite food is " + self._FavoriteFood) class Cat(Animal): _FavoriteFood = 'tuna' # Note since we override, Cat class has its own statically allocated _FavoriteFood variable, different from Animal's class Dog(Animal): _FavoriteFood = 'steak' # Likewise, the Dog class gets its own static variable. Important to note - this one static variable is shared among all instances of Dog, hence it is not dynamic! if __name__ == "__main__": whiskers = Cat() # Dynamically allocated fido = Dog() # Dynamically allocated rinTinTin = Dog() # Dynamically allocated whiskers.PetAnimal() fido.PetAnimal() rinTinTin.PetAnimal() Dog._FavoriteFood = 'milkbones' whiskers.PetAnimal() fido.PetAnimal() rinTinTin.PetAnimal() # Output is: # Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna # Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak # Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak # Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna # Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is milkbones # Thank you for petting me. But it's 13:05:02.256000, you should feed me. My favorite food is milkbones 

Others have answered the broad strokes pretty well, so I’ll throw in a few details.

  1. Stack and heap need not be singular. A common situation in which you have more than one stack is if you have more than one thread in a process. In this case each thread has its own stack. You can also have more than one heap, for example some DLL configurations can result in different DLLs allocating from different heaps, which is why it’s generally a bad idea to release memory allocated by a different library.

  2. In C you can get the benefit of variable length allocation through the use of alloca , which allocates on the stack, as opposed to alloc, which allocates on the heap. This memory won’t survive your return statement, but it’s useful for a scratch buffer.

  3. Making a huge temporary buffer on Windows that you don’t use much of is not free. This is because the comstackr will generate a stack probe loop that is called every time your function is entered to make sure the stack exists (because Windows uses a single guard page at the end of your stack to detect when it needs to grow the stack. If you access memory more than one page off the end of the stack you will crash). Exemple:

 void myfunction() { char big[10000000]; // Do something that only uses for first 1K of big 99% of the time. } 

Others have directly answered your question, but when trying to understand the stack and the heap, I think it is helpful to consider the memory layout of a traditional UNIX process (without threads and mmap() -based allocators). The Memory Management Glossary web page has a diagram of this memory layout.

The stack and heap are traditionally located at opposite ends of the process’s virtual address space. The stack grows automatically when accessed, up to a size set by the kernel (which can be adjusted with setrlimit(RLIMIT_STACK, ...) ). The heap grows when the memory allocator invokes the brk() or sbrk() system call, mapping more pages of physical memory into the process’s virtual address space.

In systems without virtual memory, such as some embedded systems, the same basic layout often applies, except the stack and heap are fixed in size. However, in other embedded systems (such as those based on Microchip PIC microcontrollers), the program stack is a separate block of memory that is not addressable by data movement instructions, and can only be modified or read indirectly through program flow instructions (call, return, etc.). Other architectures, such as Intel Itanium processors, have multiple stacks . In this sense, the stack is an element of the CPU architecture.

I think many other people have given you mostly correct answers on this matter.

One detail that has been missed, however, is that the “heap” should in fact probably be called the “free store”. The reason for this distinction is that the original free store was implemented with a data structure known as a “binomial heap.” For that reason, allocating from early implementations of malloc()/free() was allocation from a heap. However, in this modern day, most free stores are implemented with very elaborate data structures that are not binomial heaps.

The stack is a portion of memory that can be manipulated via several key assembly language instructions, such as ‘pop’ (remove and return a value from the stack) and ‘push’ (push a value to the stack), but also call (call a subroutine – this pushes the address to return to the stack) and return (return from a subroutine – this pops the address off of the stack and jumps to it). It’s the region of memory below the stack pointer register, which can be set as needed. The stack is also used for passing arguments to subroutines, and also for preserving the values in registers before calling subroutines.

The heap is a portion of memory that is given to an application by the operating system, typically through a syscall like malloc. On modern OSes this memory is a set of pages that only the calling process has access to.

The size of the stack is determined at runtime, and generally does not grow after the program launches. In a C program, the stack needs to be large enough to hold every variable declared within each function. The heap will grow dynamically as needed, but the OS is ultimately making the call (it will often grow the heap by more than the value requested by malloc, so that at least some future mallocs won’t need to go back to the kernel to get more memory. This behavior is often customizable)

Because you’ve allocated the stack before launching the program, you never need to malloc before you can use the stack, so that’s a slight advantage there. In practice, it’s very hard to predict what will be fast and what will be slow in modern operating systems that have virtual memory subsystems, because how the pages are implemented and where they are stored is an implementation detail.

What is a stack?

A stack is a stack of objects, typically one that is neatly arranged.

Entrez la description de l'image ici

Stacks in computing architectures are regions of memory where data is added or removed in a last-in-first-out manner.
In a multi-threaded application, each thread will have its own stack.

What is a heap?

A heap is an untidy collection of things stackd up haphazardly.

Entrez la description de l'image ici

In computing architectures the heap is an area of dynamically-allocated memory that is managed automatically by the operating system or the memory manager library.
Memory on the heap is allocated, deallocated, and resized regularly during program execution, and this can lead to a problem called fragmentation.
Fragmentation occurs when memory objects are allocated with small spaces in between that are too small to hold additional memory objects.
The net result is a percentage of the heap space that is not usable for further memory allocations.

Both together

In a multi-threaded application, each thread will have its own stack. But, all the different threads will share the heap.
Because the different threads share the heap in a multi-threaded application, this also means that there has to be some coordination between the threads so that they don’t try to access and manipulate the same piece(s) of memory in the heap at the same time.

Which is faster – the stack or the heap? And why?

The stack is much faster than the heap.
This is because of the way that memory is allocated on the stack.
Allocating memory on the stack is as simple as moving the stack pointer up.

For people new to programming, it’s probably a good idea to use the stack since it’s easier.
Because the stack is small, you would want to use it when you know exactly how much memory you will need for your data, or if you know the size of your data is very small.
It’s better to use the heap when you know that you will need a lot of memory for your data, or you just are not sure how much memory you will need (like with a dynamic array).

Java Memory Model

Entrez la description de l'image ici

The stack is the area of memory where local variables (including method parameters) are stored. When it comes to object variables, these are merely references (pointers) to the actual objects on the heap.
Every time an object is instantiated, a chunk of heap memory is set aside to hold the data (state) of that object. Since objects can contain other objects, some of this data can in fact hold references to those nested objects.

You can do some interesting things with the stack. For instance, you have functions like alloca (assuming you can get past the copious warnings concerning its use), which is a form of malloc that specifically uses the stack, not the heap, for memory.

That said, stack-based memory errors are some of the worst I’ve experienced. If you use heap memory, and you overstep the bounds of your allocated block, you have a decent chance of sortingggering a segment fault. (Not 100%: your block may be incidentally contiguous with another that you have previously allocated.) But since variables created on the stack are always contiguous with each other, writing out of bounds can change the value of another variable. I have learned that whenever I feel that my program has stopped obeying the laws of logic, it is probably buffer overflow.

Simply, the stack is where local variables get created. Also, every time you call a subroutine the program counter (pointer to the next machine instruction) and any important registers, and sometimes the parameters get pushed on the stack. Then any local variables inside the subroutine are pushed onto the stack (and used from there). When the subroutine finishes, that stuff all gets popped back off the stack. The PC and register data gets and put back where it was as it is popped, so your program can go on its merry way.

The heap is the area of memory dynamic memory allocations are made out of (explicit “new” or “allocate” calls). It is a special data structure that can keep track of blocks of memory of varying sizes and their allocation status.

In “classic” systems RAM was laid out such that the stack pointer started out at the bottom of memory, the heap pointer started out at the top, and they grew towards each other. If they overlap, you are out of RAM. That doesn’t work with modern multi-threaded OSes though. Every thread has to have its own stack, and those can get created dynamicly.

From WikiAnwser.

Stack

When a function or a method calls another function which in turns calls another function, etc., the execution of all those functions remains suspended until the very last function returns its value.

This chain of suspended function calls is the stack, because elements in the stack (function calls) depend on each other.

The stack is important to consider in exception handling and thread executions.

Heap

The heap is simply the memory used by programs to store variables. Element of the heap (variables) have no dependencies with each other and can always be accessed randomly at any time.

Stack

  • Very fast access
  • Don’t have to explicitly de-allocate variables
  • Space is managed efficiently by CPU, memory will not become fragmented
  • Local variables only
  • Limit on stack size (OS-dependent)
  • Variables cannot be resized

Heap

  • Variables can be accessed globally
  • No limit on memory size
  • (Relatively) slower access
  • No guaranteed efficient use of space, memory may become fragmented over time as blocks of memory are allocated, then freed
  • You must manage memory (you’re in charge of allocating and freeing variables)
  • Variables can be resized using realloc()

In the 1980s, UNIX propagated like bunnies with big companies rolling their own. Exxon had one as did dozens of brand names lost to history. How memory was laid out was at the discretion of the many implementors.

A typical C program was laid out flat in memory with an opportunity to increase by changing the brk() value. Typically, the HEAP was just below this brk value and increasing brk increased the amount of available heap.

The single STACK was typically an area below HEAP which was a tract of memory containing nothing of value until the top of the next fixed block of memory. This next block was often CODE which could be overwritten by stack data in one of the famous hacks of its era.

One typical memory block was BSS (a block of zero values) which was accidentally not zeroed in one manufacturer’s offering. Another was DATA containing initialized values, including ssortingngs and numbers. A third was CODE containing CRT (C runtime), main, functions, and libraries.

The advent of virtual memory in UNIX changes many of the constraints. There is no objective reason why these blocks need be contiguous, or fixed in size, or ordered a particular way now. Of course, before UNIX was Multics which didn’t suffer from these constraints. Here is a schematic showing one of the memory layouts of that era.

A typical 1980s style UNIX C program memory layout

  • introduction

Physical memory is the range of the physical addresses of the memory cells in which an application or system stores its data, code, and so on during execution. Memory management denotes the managing of these physical addresses by swapping the data from physical memory to a storage device and then back to physical memory when needed. The OS implements the memory management services using virtual memory. As a C# application developer you do not need to write any memory management services. The CLR uses the underlying OS memory management services to provide the memory model for C# or any other high-level language targeting the CLR.

Figure 4-1 shows physical memory that has been abstracted and managed by the OS, using the virtual memory concept. Virtual memory is the abstract view of the physical memory, managed by the OS. Virtual memory is simply a series of virtual addresses, and these virtual addresses are translated by the CPU into the physical address when needed.

Figure 4-1. CLR memory abstraction

Entrez la description de l'image ici

The CLR provides the memory management abstract layer for the virtual execution environment, using the operating memory services. The abstracted concepts the CLR uses are AppDomain, thread, stack, heapmemorymapped file, and so on. The concept of the application domain (AppDomain) gives your application an isolated execution environment.

  • Memory Interaction between the CLR and OS

By looking at the stack trace while debugging the following C# application, using WinDbg, you will see how the CLR uses the underlying OS memory management services (eg, the HeapFree method from KERNEL32.dll, the RtlpFreeHeap method from ntdll.dll) to implement its own memory model:

 using System; namespace CH_04 { class Program { static void Main(ssortingng[] args) { Book book = new Book(); Console.ReadLine(); } } public class Book { public void Print() { Console.WriteLine(ToSsortingng()); } } } 

The comstackd assembly of the program is loaded into WinDbg to start debugging. You use the following commands to initialize the debugging session:

0:000> sxe ld clrjit

0:000> g

0:000> .loadby sos clr

0:000> .load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll

Then, you set a breakpoint at the Main method of the Program class, using the !bpmd command:

0:000>!bpmd CH_04.exe CH_04.Program.Main

To continue the execution and break at the breakpoint, execute the g command:

0:000> g

When the execution breaks at the breakpoint, you use the !eestack command to view the stack trace details of all threads running for the current process. The following output shows the stack trace for all the threads running for the application CH_04.exe:

0:000> !eestack


Thread 0

Current frame: (MethodDesc 00233800 +0 CH_04.Program.Main(System.Ssortingng[]))

ChildEBP RetAddr Caller, Callee

0022ed24 5faf21db clr!CallDescrWorker+0x33

/ trace removed /

0022f218 77712d68 ntdll!RtlFreeHeap+0x142, calling ntdll!RtlpFreeHeap

0022f238 771df1ac KERNEL32!HeapFree+0x14, calling ntdll!RtlFreeHeap

0022f24c 5fb4c036 clr!EEHeapFree+0x36, calling KERNEL32!HeapFree

0022f260 5fb4c09d clr!EEHeapFreeInProcessHeap+0x24, calling clr!EEHeapFree

0022f274 5fb4c06d clr!operator delete[]+0x30, calling clr!EEHeapFreeInProcessHeap / trace removed /

0022f4d0 7771316f ntdll!RtlpFreeHeap+0xb7a, calling ntdll!_SEH_epilog4

0022f4d4 77712d68 ntdll!RtlFreeHeap+0x142, calling ntdll!RtlpFreeHeap

0022f4f4 771df1ac KERNEL32!HeapFree+0x14, calling ntdll!RtlFreeHeap

/ trace removed /

This stack trace indicates that the CLR uses OS memory management services to implement its own memory model. Any memory operation in.NET goes via the CLR memory layer to the OS memory management layer.

Figure 4-2 illustrates a typical C# application memory model used by the CLR at runtime.

Figure 4-2 . A typical C# application memory model entrer la description de l'image ici

The CLR memory model is tightly coupled with the OS memory management services. To understand the CLR memory model, it is important to understand the underlying OS memory model. It is also crucial to know how the physical memory address space is abstracted into the virtual memory address space, the ways the virtual address space is being used by the user application and system application, how virtual-to-physical address mapping works, how memory-mapped file works, and so on. This background knowledge will improve your grasp of CLR memory model concepts, including AppDomain, stack, and heap.

For more information, refer to this book:

C# Deconstructed: Discover how C# works on the .NET Framework

This book + ClrViaC# + Windows Internals are excellent resources to known .net framework in depth and relation with OS.

In Sort

A stack is used for static memory allocation and a heap for dynamic memory allocation, both stored in the computer’s RAM.


In Detail

The Stack

The stack is a “LIFO” (last in, first out) data structure, that is managed and optimized by the CPU quite closely. Every time a function declares a new variable, it is “pushed” onto the stack. Then every time a function exits, all of the variables pushed onto the stack by that function, are freed (that is to say, they are deleted). Once a stack variable is freed, that region of memory becomes available for other stack variables.

The advantage of using the stack to store variables, is that memory is managed for you. You don’t have to allocate memory by hand, or free it once you don’t need it any more. What’s more, because the CPU organizes stack memory so efficiently, reading from and writing to stack variables is very fast.

More can be found here .


The Heap

The heap is a region of your computer’s memory that is not managed automatically for you, and is not as tightly managed by the CPU. It is a more free-floating region of memory (and is larger). To allocate memory on the heap, you must use malloc() or calloc(), which are built-in C functions. Once you have allocated memory on the heap, you are responsible for using free() to deallocate that memory once you don’t need it any more.

If you fail to do this, your program will have what is known as a memory leak. That is, memory on the heap will still be set aside (and won’t be available to other processes). As we will see in the debugging section, there is a tool called Valgrind that can help you detect memory leaks.

Unlike the stack, the heap does not have size ressortingctions on variable size (apart from the obvious physical limitations of your computer). Heap memory is slightly slower to be read from and written to, because one has to use pointers to access memory on the heap. We will talk about pointers shortly.

Unlike the stack, variables created on the heap are accessible by any function, anywhere in your program. Heap variables are essentially global in scope.

More can be found here .


Variables allocated on the stack are stored directly to the memory and access to this memory is very fast, and its allocation is dealt with when the program is comstackd. When a function or a method calls another function which in turns calls another function, etc., the execution of all those functions remains suspended until the very last function returns its value. The stack is always reserved in a LIFO order, the most recently reserved block is always the next block to be freed. This makes it really simple to keep track of the stack, freeing a block from the stack is nothing more than adjusting one pointer.

Variables allocated on the heap have their memory allocated at run time and accessing this memory is a bit slower, but the heap size is only limited by the size of virtual memory. Elements of the heap have no dependencies with each other and can always be accessed randomly at any time. You can allocate a block at any time and free it at any time. This makes it much more complex to keep track of which parts of the heap are allocated or free at any given time.

Entrez la description de l'image ici

You can use the stack if you know exactly how much data you need to allocate before comstack time, and it is not too big. You can use the heap if you don’t know exactly how much data you will need at runtime or if you need to allocate a lot of data.

In a multi-threaded situation each thread will have its own completely independent stack, but they will share the heap. The stack is thread specific and the heap is application specific. The stack is important to consider in exception handling and thread executions.

Each thread gets a stack, while there’s typically only one heap for the application (although it isn’t uncommon to have multiple heaps for different types of allocation).

Entrez la description de l'image ici

At run-time, if the application needs more heap, it can allocate memory from free memory and if the stack needs memory, it can allocate memory from free memory allocated memory for the application.

Even, more detail is given here and here .


Now come to your question’s answers .

To what extent are they controlled by the OS or language runtime?

The OS allocates the stack for each system-level thread when the thread is created. Typically the OS is called by the language runtime to allocate the heap for the application.

More can be found here .

What is their scope?

Already given in top.

“You can use the stack if you know exactly how much data you need to allocate before comstack time, and it is not too big. You can use the heap if you don’t know exactly how much data you will need at runtime or if you need to allocate a lot of data.”

More can be found in here .

What determines the size of each of them?

The size of the stack is set by OS when a thread is created. The size of the heap is set on application startup, but it can grow as space is needed (the allocator requests more memory from the operating system).

What makes one faster?

Stack allocation is much faster since all it really does is move the stack pointer. Using memory pools, you can get comparable performance out of heap allocation, but that comes with a slight added complexity and its own headaches.

Also, stack vs. heap is not only a performance consideration; it also tells you a lot about the expected lifetime of objects.

Details can be found from here .

A couple of cents: I think, it will be good to draw memory graphical and more simple:

This is my vision of process memory construction with simplification for more easy understanding wht happening

Arrows – show where grow stack and heap, process stack size have limit, defined in OS, thread stack size limits by parameters in thread create API usually. Heap usually limiting by process maximum virtual memory size, for 32 bit 2-4 GB for example.

So simple way: process heap is general for process and all threads inside, using for memory allocation in common case with something like malloc() .

Stack is quick memory for store in common case function return pointers and variables, processed as parameters in function call, local function variables.

OK, simply and in short words, they mean ordered and not ordered …!

Stack : In stack items, things get on the top of each-other, means gonna be faster and more efficient to be processed!…

So there is always an index to point the specific item, also processing gonna be faster, there is relationship between the items as well!…

Heap : No order, processing gonna be slower and values are messed up together with no specific order or index… there are random and there is no relationship between them… so execution and usage time could be vary…

I also create the image below to show how they may look like:

entrer la description de l'image ici

Since some answers went nitpicking, I’m going to consortingbute my mite.

Surprisingly, no one has mentioned that multiple (ie not related to the number of running OS-level threads) call stacks are to be found not only in exotic languages (PostScript) or platforms (Intel Itanium), but also in fibers , green threads and some implementations of coroutines .

Fibers, green threads and coroutines are in many ways similar, which leads to much confusion. The difference between fibers and green threads is that the former use cooperative multitasking, while the latter may feature either cooperative or preemptive one (or even both). For the distinction between fibers and coroutines, see here .

In any case, the purpose of both fibers, green threads and coroutines is having multiple functions executing concurrently, but not in parallel (see this SO question for the distinction) within a single OS-level thread, transferring control back and forth from one another in an organized fashion.

When using fibers, green threads or coroutines, you usually have a separate stack per function. (Technically, not just a stack but a whole context of execution is per function. Most importantly, CPU registers.) For every thread there’re as many stacks as there’re concurrently running functions, and the thread is switching between executing each function according to the logic of your program. When a function runs to its end, its stack is destroyed. So, the number and lifetimes of stacks are dynamic and are not determined by the number of OS-level threads!

Note that I said ” usually have a separate stack per function”. There’re both stackful and stackless implementations of couroutines. Most notable stackful C++ implementations are Boost.Coroutine and Microsoft PPL ‘s async/await . (However, C++’s resumable functions (aka ” async and await “), which were proposed to C++17, are likely to use stackless coroutines.)

Fibers proposal to the C++ standard library is forthcoming. Also, there’re some third-party libraries . Green threads are extremely popular in languages like Python and Ruby.

stack , heap and data of each process in virtual memory:

stack, heap and static data

I have something to share with you, although major points are already penned.

Stack

  • Very fast access.
  • Stored in RAM.
  • Function calls are loaded here along with the local variables and function parameters passed.
  • Space is freed automatically when program goes out of a scope.
  • Stored in sequential memory.

Heap

  • Slow access comparatively to Stack.
  • Stored in RAM.
  • Dynamically created variables are stored here, which later requires freeing the allocated memory after use.
  • Stored wherever memory allocation is done, accessed by pointer always.

Interesting note:

  • Should the function calls had been stored in heap, it would had resulted in 2 messy points:
    1. Due to sequential storage in stack, execution is faster. Storage in heap would have resulted in huge time consumption thus resulting whole program to execute slower.
    2. If functions were stored in heap (messy storage pointed by pointer), there would have been no way to return to the caller address back (which stack gives due to sequential storage in memory).

Feedbacks are wellcomed.

A lot of answers are correct as concepts, but we must note that a stack is needed by the hardware (ie microprocessor) to allow calling subroutines (CALL in assembly language..). (OOP guys will call it methods )

On the stack you save return addresses and call → push / ret → pop is managed directly in hardware.

You can use the stack to pass parameters.. even if it is slower than using registers (would a microprocessor guru say or a good 1980s BIOS book…)

  • Without stack no microprocessor can work. (we can’t imagine a program, even in assembly language, without subroutines/functions)
  • Without the heap it can. (An assembly language program can work without, as the heap is a OS concept, as malloc, that is a OS/Lib call.

Stack usage is faster as:

  • Is hardware, and even push/pop are very efficient.
  • malloc requires entering kernel mode, use lock/semaphore (or other synchronization primitives) executing some code and manage some structures needed to keep track of allocation.