web-dev-qa-db-fra.com

Où sont stockés tous les membres statiques?

J'essaie d'apprendre comment C # gère la mémoire. Je suis coincé sur des éléments statiques, j'ai lu de nombreux blogs et articles sur ce sujet, mais je ne trouve pas de réponse tout à fait satisfaisante.

Définissons un bloc de code pour aider à trouver la réponse.

class myClass
{
    static string myStr = "String Data";
    static int myInt = 12;
}

Avant de partager votre réponse, permettez-moi de partager mes conclusions que je connais à ce sujet. N'hésitez pas à être d'accord ou en désaccord et aidez-moi à trouver la bonne réponse.

  • La statique est juste pour la durée de vie.
  • Un type de référence statique (myStr), restera sur le tas, pour la durée de vie.
  • Un type de valeur statique (myInt) ira sur la pile pour la durée de vie.

Ce qui m'embrouille, ce sont quelques réponses que j'ai trouvées sur internet, à ce sujet.

Confusion numéro 1:

Lorsque votre programme démarre, il charge tous les assemblys associés dans un AppDomain. Lorsque l'assembly est chargé, tous les constructeurs statiques sont appelés, y compris les champs statiques. Ils vivront là-bas et la seule façon de les décharger est de décharger l'AppDomain.

Dans les lignes ci-dessus, il est mentionné explicitement que tous les éléments statiques stockés sur AppDomain. Alors pourquoi tout le monde sur Internet dit que les éléments "statiques" sont stockés sur le tas/la pile?

Confusion numéro 2:

Chaque variable statique est stockée sur le tas, qu'elle soit déclarée dans un type de référence ou un type de valeur.

Si chaque variable statique stockée sur le tas. Alors pourquoi certains disent que les variables statiques de type valeur sont stockées sur la pile?

Aidez-moi à connecter mes points pour comprendre la gestion de la mémoire des variables statiques en C #. Merci beaucoup pour votre précieux temps :)

39
Ali Asad

Tout d'abord, notez que tout cela est un détail d'implémentation. La seule chose que le runtime garantit est:

  • Lorsque vous demandez un champ statique, il est là
  • Un constructeur statique est exécuté à un moment donné avant d'utiliser le type

C'est à peu près ça. Tout le reste est un détail d'implémentation - la spécification ne se soucie pas de la pile, du tas ou de toute autre chose. Cela dépend de l'implémentation du runtime, et un runtime valide pourrait tout mettre sur la pile, s'il le souhaite, ou sur le tas. Et n'oubliez pas les registres.

Voyons maintenant certaines des idées fausses que vous avez déjà réussi à capter:

  • La statique est juste pour la durée de vie - oui. Il ne dit rien sur quand ni où il est stocké - juste qu'il est disponible lorsque vous l'avez demandé. Un runtime conforme est libre d'utiliser la mémoire qu'il veut, ou même de ne jamais charger les champs en mémoire (par exemple en le conservant dans l'image, qui est déjà en mémoire de toute façon)
  • Statique restera sur le tas, pour la durée de vie - très probablement, oui. Mais cela ne fait pas partie de la spécification, et un runtime conforme peut le stocker où il veut, ou nulle part, tant que les garanties appropriées sont respectées. N'oubliez pas non plus que "pour la durée de vie" signifie "au moins pour la durée de vie de l'AppDomain"; il peut ou non être libéré lorsque le domaine est déchargé.
  • Le type de valeur statique ira sur la pile, pour la durée de vie - très probablement, non. Encore une fois, un détail d'implémentation, mais la pile a une sémantique complètement différente de celle qui a du sens pour une valeur statique. Et le point suivant vous donnera plus de raisons pour lesquelles:
  • Lorsque l'assemblable est chargé, tous les constructeurs statiques sont appelés, y compris les champs statiques. - Non. Il n'y a pas une telle exigence et aucune garantie. Si vous vous en remettez à cela, votre programme va s'arrêter (et je l'ai déjà vu plusieurs fois auparavant). Encore une fois, un détail d'implémentation, mais dans les implémentations MSCLR actuelles, les statistiques ont tendance à être allouées dans un tas qui leur est propre, et un certain temps avant le type dans lequel elles sont définies est nécessaire. Vous pouvez facilement voir cela si vous lancez une exception dans un constructeur statique - cela provoquera un TypeLoadException, très probablement dans une méthode qui fait d'abord référence au type (inutile de dire que cela peut rendre le débogage des statistiques délicates).
  • Les types de référence vont sur le tas, les types de valeur vont sur la pile. - Non. Cela confond le mécanisme avec la sémantique. La seule différence entre les deux est leur sémantique - tout le reste dépend de l'implémentation. Si un runtime peut conserver la sémantique de référence pour les types de référence sur la pile, c'est parfaitement valide. Et même avec les exécutions MSCLR actuelles, les types de valeurs sont stockés en permanence sur le tas, chaque fois qu'ils sont encadrés ou membres d'un type de référence, par exemple.

Certaines personnes peuvent être confuses. Certains ne comprennent pas la différence entre le contrat et les implémentations pratiques. Certains ne savent tout simplement pas de quoi ils parlent. J'aimerais qu'il y ait un moyen facile de savoir lequel est lequel, mais il n'y en a pas. En cas de doute, vous pouvez consulter les spécifications C #/CLR, mais cela ne vous renseigne que sur le contrat, pas sur la réalité pratique.

L'intérêt de la mémoire gérée est que vous n'êtes pas censé vous soucier de ces détails d'implémentation. Bien sûr, comme toute abstraction, elle fuit - et il est logique de savoir comment les choses se passent réellement, jusqu'aux micro-instructions du processeur, à la mise en cache de la mémoire, etc., à travers toutes les différentes couches et abstractions. Mais il n'y a rien à sur lequel s'appuyer - l'implémentation peut changer à tout moment, et cela s'est produit à plusieurs reprises dans le passé.

56
Luaan

Chaque fois qu'un processus est chargé dans la RAM, nous pouvons dire que la mémoire est grossièrement divisée en trois zones (dans ce processus): Stack, Heap et Static (qui, en .NET, est en fait une zone spéciale à l'intérieur de Heap uniquement connue sous le nom de Tas à haute fréquence).

La partie statique contient les variables et méthodes membres "statiques". Qu'est-ce qui est exactement statique? Les méthodes et variables qui ne nécessitent pas la création d'une instance d'une classe sont définies comme étant statiques

En savoir plus ici .

6
Amir Popovich

Il existe une instance de la classe créée, avec tous les membres statiques initialisés.

Les membres des classes statiques sont normalement stockés sur le tas, les membres des types valeur sont normalement stockés sur la pile.

Cela ne doit pas être le cas, vous pouvez lire this blog pour plus d'informations.

Il s'agit d'un des concepteurs de langage de C #, Eric Lippert.

Le blog montre que contrairement aux connaissances normales, il n'est pas sûr que les types de valeur se trouvent sur la pile et que les types de référence soient sur le tas, mais ils le sont généralement.

Ce n'est tout simplement pas spécifié dans la spécification.

2
Mafii