88 votes

Allocation de mémoire : Pile ou tas ?

Je m'embrouille avec les bases de l'allocation de mémoire entre Pile et tas . D'après la définition standard (ce que tout le monde dit), tout Types de valeurs sera alloué à un Pile y Référence Les types vont aller dans le Amas .

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 passe-t-elle en C# ? Est-ce que l'objet de MyClass (c'est-à-dire, m ) seront entièrement alloués au tas ? C'est-à-dire, int myInt y string myString les deux vont aller au tas ?

Ou bien, l'objet sera divisé en deux parties et sera alloué aux deux emplacements mémoire, à savoir la pile et le tas ?

0 votes

Cela répond-il à votre question ? Que sont la pile et le tas et où sont-ils ?

74voto

Gabe Points 49718

Vous devez vous poser la question suivante sont alloués en tant que détail d'implémentation. L'endroit exact où sont stockés les bits d'un objet n'a pas d'importance pour vous. Il peut être important de savoir 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 commenciez à devoir optimiser le comportement du ramassage des ordures.

Alors que les types de référence sont toujours alloués sur le tas dans les implémentations actuelles, les types de valeur mai ê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 encapsulée et non évocatrice, 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 se retrouvera sur le tas.
  • S'il est emballé, il finira sur le tas.
  • S'il est dans un tableau, il finira sur le tas.
  • Si c'est une variable statique, elle se retrouvera 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 se retrouvera sur le tas.
  • S'il est créé par du 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 entendu, je m'en voudrais de ne pas mentionner les articles d'Eric Lippert sur le sujet :

0 votes

Sauf bien sûr jusqu'à ce que cela ait une réelle importance, auquel cas il est utile de comprendre ce qui se passe réellement.

1 votes

Ed : Exactement quand est-ce que ça compte ?

1 votes

@Gabe : L'endroit où les bits sont stockés a de l'importance. Par exemple, si vous déboguez un crash dump, vous n'irez pas très loin si vous ne savez pas où chercher les objets/données.

60voto

Mud Points 12084

m est alloué sur le tas, et cela inclut myInt . Les situations où les types primitifs (et les structs) sont alloués sur la pile sont lors de l'invocation de la méthode, qui alloue de la place pour les variables locales sur la pile (parce que 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 se trouve quelque part sur le tas (et doit être accessible via la commande this pointeur).

7 votes

Il est important de se rappeler que "la pile" et "le tas" sont en réalité des détails de mise en œuvre dans .NET. Il est parfaitement possible de créer une implémentation légale de C# qui n'utilise pas du tout l'allocation basée sur la pile.

5 votes

Je suis d'accord qu'ils devraient être traité de cette façon, mais il n'est pas tout à fait vrai qu'il s'agit de détails purement liés à la mise en œuvre. C'est explicitement mentionné dans la documentation publique de l'API et dans la norme du langage (EMCA-334, ISO/IEC 23270:2006) (par exemple, "Les valeurs des structures sont stockées "sur la pile". Les programmeurs prudents peuvent parfois améliorer les performances par une utilisation judicieuse des structures"). Mais, oui, si la vitesse d'allocation du tas est un goulot d'étranglement pour votre application, vous vous y prenez probablement mal (ou vous utilisez le mauvais langage).

23voto

Marc Gravell Points 482669

"Tous les types de VALEURS seront alloués à la pile" est très, très faux ; les variables struct. peut vivent sur la pile, en tant que variables de méthode. Cependant, les champs d'un type vivre 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. où que ce soit qui structurent les vies.

Variables de la méthode Even peut être sur le tas, s'ils sont capturé (lambda/anon-méthode), ou une partie (par exemple) d'un bloc itérateur.

1 votes

Et n'oubliez pas la boxe : si vous avez object x = 12; dans une méthode, le 12 sera stocké sur le tas même si c'est un entier (un type de valeur).

0 votes

Gabe : Les emplacements de stockage de type valeur contiennent les champs (publics et privés) d'un type de valeur. Les emplacements de stockage de type référence contiennent soit null ou une référence à un objet du tas de type approprié. Pour chaque type de valeur, il existe un type d'objet de tas correspondant. Si l'on tente de stocker un type de valeur dans un emplacement de type référence, un nouvel objet de type objet de tas correspondant sera créé, tous les champs seront copiés dans ce nouvel objet et une référence à l'objet sera stockée dans l'emplacement de type référence. C# prétend que le type de valeur et le type d'objet sont identiques, mais...

0 votes

...un tel point de vue ajoute de la confusion plutôt que de la compréhension. Un produit non emballé List<T>.Enumerator qui est stocké dans une variable de ce type aura une sémantique de valeur, parce que c'est un type de valeur. A List<T>.Enumerator qui est stocké dans une variable de type IEnumerator<T> se comportera toutefois comme un type de référence. Si l'on considère ce dernier comme un type différent du premier, la différence de comportement est facilement explicable. En prétendant qu'il s'agit du même type, il est beaucoup plus difficile de raisonner à leur sujet.

13voto

1voto

Saurabh Points 11097

Mesures simples

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

Il est donc préférable de comprendre comment fonctionnent les types de valeur et de référence. Le type de valeur sera copié par la valeur, c'est-à-dire que si vous passez un type de valeur comme paramètre à une FONCTION, il sera copié par nature, ce qui signifie que vous aurez une copie totalement nouvelle.

Les types de référence sont transmis par référence (ne considérez pas que la référence stockera à nouveau une adresse dans des versions futures, elle peut être stockée dans d'autres structures de données).

donc dans votre cas

myInt est un int qui est encapsulé dans une classe qui, bien sûr, est un type de référence, donc il sera lié à l'instance de la classe qui sera stockée sur 'THE HEAP'.

Je vous suggère de commencer à lire les blogs écrits par ERIC LIPPERTS.

Le blog d'Eric

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X