Allocation de mémoire: pile vs tas?

Je suis confondu avec les bases de l'allocation de mémoire entre pile vs tas . Selon la définition standard (ce que tout le monde dit), tous les Types de valeur seront alloués sur une pile et les Types Reference iront dans le tas .

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 se produira-t-elle en c#? L'objet de MyClass (c'est-à-dire m) sera-t-il complètement alloué au tas? Autrement dit, int myInt et string myString les deux iront à tas?

Ou, l'objet sera divisé en deux parties et sera alloué aux deux emplacements de mémoire qui est, pile et tas?

66
demandé sur Mangesh 2010-12-20 09:02:25

8 réponses

m est alloué sur le tas, et qui comprend myInt. Les situations où les types primitifs (et les structures) sont alloués sur la pile sont pendant l'invocation de la méthode, ce qui alloue de la place pour les variables locales sur la pile (car c'est 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).

45
répondu Mud 2010-12-20 06:08:55

Vous devriez considérer la question de où les objets sont alloués en tant que détail d'implémentation. Peu importe pour vous exactement où les bits d'un objet sont stockés. Peu importe si un objet est un type de référence ou un type de valeur, mais vous n'avez pas à vous soucier de l'endroit où il sera stocké jusqu'à ce que vous deviez optimiser le comportement de récupération de place.

Alors que les types de référence sont toujours alloués sur le tas dans les implémentations en cours, les types de valeur peuvent être alloué sur la pile-mais ne le sont pas nécessairement. Un type de valeur n'est alloué sur la pile que s'il s'agit d'une variable locale ou Temporaire Non échappante non encadrée qui n'est pas contenue dans un type de référence et qui n'est pas allouée dans un registre.

  • si un type de valeur fait partie d'une classe (comme dans votre exemple), il finira sur le tas.
  • S'il est en boîte, il finira sur le tas.
  • S'il est dans un tableau, il finira sur le tas.
  • Si c'est une variable statique, elle retrouvez sur le tas.
  • S'il est capturé par une fermeture, il finira sur le tas.
  • S'il est utilisé dans un itérateur ou un bloc asynchrone, il finira sur 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 que j'ai manqué?

Bien sûr, je serais négligent si Je ne Liais pas aux messages D'Eric Lippert sur le sujet:

51
répondu Gabe 2014-06-26 13:58:45

"Tous les types de valeurs seront alloués à la pile" est très, très faux; les variables struct peuvent vivre sur la pile, en tant que variables de méthode. Cependant, les champs d'un type vivent avec ce type . Si le type de déclaration d'un champ est une classe, les valeurs sont sur le tas en tant que Partie de cet objet. Si le type de déclaration d'un champ est une structure, les champs font partie de cette structure where-ever Cette structure vit.

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

20
répondu Marc Gravell 2010-12-20 06:09:22

Mesures Simples

Le type de valeur peut être stred sur la pile, c'est le détail d'implémentation qu'il peut être alloué à la structure de données futuristist.

Donc, il est préférable de comprendre comment fonctionne la valeur et le type de référence , le type de valeur sera copié par valeur, ce qui signifie que lorsque vous passez un type de valeur en tant que paramètre à une fonction, il sera copié par nature signifie que vous aurez une nouvelle copie totale.

Les types de référence sont passés par référence (againg ne considère pas reference stockera à nouveau une adresse dans certaines versions futures ,elle peut être stockée sur d'autres structures de données.)

Donc, dans votre cas,

MyInt est un int qui est ecapsulé dans une classe qui offcourse un type de référence donc il sera lié à l'instance de la classe qui sera stockée sur 'le tas'.

Je suggère, vous pouvez commencer à lire des blogs écrits par ERIC LIPPERTS.

Le Blog D'Eric

1
répondu TalentTuner 2010-12-20 07:07:08

Chaque fois qu'un objet est créé, il entre dans la zone de mémoire appelée tas. Les variables primitives comme int et double sont alloués dans la pile, s'ils sont des variables de méthode locales et dans le tas s'ils sont membres variable . Dans les méthodes les variables locales sont poussées dans la pile lorsqu'une méthode est invoquée et le pointeur de pile est décrémenté lorsqu'un appel de méthode est terminé. Dans une application multithread chaque thread aura sa propre pile mais partagera le même tas. C'est pourquoi les soins de devrait être pris dans votre code pour éviter tout problèmes d'accès simultanés dans l'espace de tas. La pile est threadsafe (chaque thread aura sa propre pile) mais le heap n'est pas thread safe sauf si gardé avec la synchronisation via votre code.

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

1
répondu Rohit Goyal 2015-04-06 18:34:49

Pile

Le stack est un bloc de mémoire pour le stockage de local variables et parameters. La pile se développe et se rétrécit logiquement à mesure qu'une fonction est entrée et sortie.

Considérons 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é, un nouveau type int est alloué sur la pile, et chaque fois que la méthode de sortie, le type int est désalloué.


Tas

  • le tas est un bloc de mémoire dans lequel réside objects (c'est-à-dire reference-type instances). Lorsqu'un nouvel objet est créé, il est alloué sur le tas, et une référence à cet objet est retourné. Pendant l'exécution d'un programme, le tas commence à se remplir à mesure que de nouveaux objets sont créés. Le runtime a un garbage collector qui désalloue périodiquement les objets du tas, de sorte que votre programme ne s'exécute pas Out Of Memory. Un objet est admissible à la désallocation dès qu'il n'est pas référencé par quelque chose qui est lui même alive.
  • le tas stocke également static fields. Contrairement aux objets alloués sur le tas (qui peuvent être collectés), these live until the application domain is torn down.

Considérons 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 écrivons son 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 copiez cette référence à ref3. Même si ref2 n'est pas utilisé après ce point, ref3 conserve le même objet StringBuilder en vie-en veillant à ce qu'il ne devienne pas éligible pour la collection jusqu'à ce que nous ayons fini d'utiliser ref3.

Les instances de type valeur (et les références d'objet) vivent partout où la variable annoncé. 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 vit sur le tas.

1
répondu Sina Lotfi 2018-01-28 18:22:26

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 stocke dans le tas. Par conséquent Myint et myString magasin dans le tas. Notez que m est seulement une référence (une adresse à la mémoire) et est sur la pile principale. lorsque m est désalloué GC efface 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
répondu ali afshari 2018-03-30 12:50:55