web-dev-qa-db-fra.com

Allocation de mémoire: Stack vs Heap?

Je suis confus avec les bases de l'allocation de mémoire entre Stack vs Heap. Selon la définition standard (tout le monde le dit), tous les types Value seront affectés aux types Stack et Reference iront au Heap

Considérons maintenant l'exemple suivant:

class MyClass
{
    int myInt = 0;    
    string myString = "Something";
}

class Program
{
    static void Main(string[] args)
    {
       MyClass m = new MyClass();
    }
}

Maintenant, comment l'allocation de mémoire va-t-elle se passer en c #? L'objet de MyClass (c'est-à-dire m) sera-t-il complètement attribué au tas? C'est-à-dire que int myInt et string myString iront tous deux au tas? 

Ou, l'objet sera divisé en deux parties et sera alloué aux deux emplacements de mémoire que sont Stack et Heap?

72
Mrinal

m est alloué sur le tas, et cela inclut myInt. Les situations dans lesquelles des types primitifs (et des structures) sont alloués sur la pile se produisent lors de l'appel de la méthode, ce qui alloue de la place pour les variables locales sur la pile (car plus rapide). Par exemple:

class MyClass
{
    int myInt = 0;

    string myString = "Something";

    void Foo(int x, int y) {
       int rv = x + y + myInt;
       myInt = 2^rv;
    }
}

rv, x, y seront tous sur la pile. myInt est quelque part sur le tas (et doit être accessible via le pointeur this).

51
Mud

Vous devriez considérer la question de objets sont alloués comme un détail d'implémentation. Peu importe pour vous où sont stockés les bits d’un objet. Le fait qu'un objet soit un type de référence ou un type de valeur peut avoir de l'importance, mais vous n'avez pas à vous soucier de l'endroit où il sera stocké avant d'avoir à optimiser le comportement de la récupération de place.

Alors que les types de référence sont toujours alloués sur le tas dans les implémentations actuelles, les types de valeur peuvent être alloués sur la pile - mais ne le sont pas nécessairement. Un type de valeur n'est alloué sur la pile que lorsqu'il s'agit d'une variable locale ou temporaire non-échappée sans boîte qui n'est pas contenue dans un type de référence ni allouée dans un registre.

  • Si un type de valeur fait partie d'une classe (comme dans votre exemple), il se retrouvera dans le tas.
  • Si c'est en boîte, ça va finir sur le tas.
  • Si c'est dans un tableau, ça finira sur le tas.
  • Si c'est une variable statique, elle se retrouvera dans le tas.
  • Si elle est capturée par une fermeture, elle finira sur le tas.
  • S'il est utilisé dans un bloc itérateur ou asynchrone, il se retrouvera dans le tas.
  • S'il est créé par un code non sécurisé ou non géré, il peut être alloué dans n'importe quel type de structure de données (pas nécessairement une pile ou un tas).

Y a-t-il quelque chose qui m'a manqué?

Bien sûr, je m'en voudrais de ne pas faire un lien vers les articles d'Eric Lippert sur le sujet:

54
Gabe

"Tous les types VALUE seront affectés à Stack" est très, très faux; struct variables can live sur la pile, en tant que variables de méthode. Cependant, les champs d'un type vivent avec ce type . Si le type déclarant d'un champ est une classe, les valeurs sont sur le tas en tant que part de cet objet. Si le type déclarant d'un champ est une structure, les champs font partie de cette structure où que ce soit cette structure vit.

Même les variables de méthode peuvent se trouvent sur le tas, si elles sont capturées (lambda/anon-method), ou font partie d’un bloc itérateur, par exemple.

20
Marc Gravell
10
jgauffin

Empiler

stack est un bloc de mémoire pour stocker local variables et parameters. La pile augmente et diminue logiquement au fur et à mesure que la fonction est entrée et sortie.

Considérez la méthode suivante:

public static int Factorial (int x)
{
    if (x == 0) 
    {
        return 1;
    }

    return x * Factorial (x - 1);
}

Cette méthode est récursive, ce qui signifie qu'elle s'appelle elle-même. Chaque fois que la méthode est entrée, un nouveau int est alloué sur la pile , et à chaque sortie de la méthode, l'int est désalloué .


Tas

  • Le segment de mémoire est un bloc de mémoire dans lequel réside objects (c'est-à-dire reference-type instances). Chaque fois qu'un nouvel objet est créé, il est alloué sur le segment de mémoire et une référence à cet objet est renvoyée. Lors de l’exécution d’un programme, le tas commence à se remplir à mesure que de nouveaux objets sont créés. Le runtime dispose d'un ramasse-miettes qui libère périodiquement les objets du tas, de sorte que votre programme n'exécute pas Out Of Memory. Un objet est éligible pour la désallocation dès qu’il n’est référencé par aucun élément lui-même alive.
  • Le tas stocke également static fields. these live until the application domain is torn down, contrairement aux objets alloués sur le tas (qui peuvent être récupérés avec ordures).

Considérez la méthode suivante:

using System;
using System.Text;

class Test
{
    public static void Main()
    {
        StringBuilder ref1 = new StringBuilder ("object1");
        Console.WriteLine (ref1);
        // The StringBuilder referenced by ref1 is now eligible for GC.

        StringBuilder ref2 = new StringBuilder ("object2");
        StringBuilder ref3 = ref2;
        // The StringBuilder referenced by ref2 is NOT yet eligible for GC.
        Console.WriteLine (ref3); // object2
    }
}    

Dans l'exemple ci-dessus, nous commençons par créer un objet StringBuilder référencé par la variable ref1, puis en écrivons le contenu. Cet objet StringBuilder est alors immédiatement éligible pour la récupération de place, car rien ne l'utilise par la suite. Ensuite, nous créons un autre StringBuilder référencé par la variable ref2 et copions cette référence dans ref3. Même si ref2 n'est plus utilisé après ce moment, ref3 conserve le même objet StringBuilder en vie, afin de s'assurer qu'il ne devient pas éligible pour la collection avant que nous ayons fini d'utiliser ref3.

Les instances de type valeur (et les références d'objet) sont actives partout où la variable était déclaré. Si l'instance a été déclarée en tant que champ dans un type de classe ou en tant qu'élément de tableau, cette instance réside sur le tas.

1
Sina Lotfi

mesures simples

Le type de valeur peut être défini sur THE STACK, c’est le détail de la mise en oeuvre qui peut être attribué à la structure de données futuriste.

il est donc préférable de comprendre le fonctionnement de la valeur et du type de référence. Le type de valeur sera copié par valeur, ce qui signifie que lorsque vous transmettez un type de valeur en tant que paramètre à une FUNCTION, il sera copié par nature, ce qui signifie que vous obtiendrez une nouvelle copie totale. .

Les types de référence sont passés par référence (car ils ne considèrent pas que référence stockera à nouveau une adresse dans certaines versions futures, elle pourrait être stockée dans d'autres structures de données.)

donc dans ton cas 

myInt est un int qui est condensé dans une classe qui déloge un type de référence de sorte qu'il sera lié à l'instance de la classe qui sera stockée sur 'THE HEAP'. 

je suggère que vous puissiez commencer à lire les blogs écrits par ERIC LIPPERTS.

Le blog d'Eric

1
TalentTuner

Chaque fois qu’un objet y est créé, il entre dans la zone de mémoire appelée tas. Les variables primitives telles que int et double sont allouées dans la pile, s’il s’agit de variables de méthode locales et dans le segment de mémoire s’il s’agit de variables membres Dans les méthodes, les variables locales sont placées dans la pile lorsqu'une méthode est appelée Et le pointeur de la pile est décrémenté lorsqu'un appel à une méthode est terminé. Dans une application multithread, chaque thread Aura sa propre pile mais partagera le même tas. C’est pourquoi, dans votre code, vous devez prendre soin d’éviter tout problème d’accès simultané dans l’espace de tas. La pile est threadsafe (chaque thread aura sa propre pile) mais le tas N'est pas thread-safe sauf s'il est protégé avec une synchronisation via votre code.

Ce lien est également utile http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/

1
Rohit Goyal

m est une référence à un objet de MyClass, donc m est stocké dans la pile du thread principal, mais l'objet de MyClass est stocké dans le segment de mémoire. Par conséquent, myInt et myString stockent dans le segment de mémoire . Notez que m est uniquement une référence (une adresse en mémoire) et se trouve sur la pile principale. Lorsque m m'est désalloué, GC supprime l'objet MyClass du tas Pour plus de détails, lisez les quatre parties de cet article https://www.c-sharpcorner.com/article/C-Sharp-heaping- vs-stacking-in-net-part-i/

0
ali afshari