2010-05-19 8 views
28

Ceci est peut-être une question à propos de nullable types.Où sont stockés en mémoire des types valables?

Où sont exactement les types de valeur NULL (int? ...) stockés en mémoire? D'abord j'ai pensé que c'est assez clair, car Nullable<T> est struct et ce sont des types de valeur. Ensuite, j'ai trouvé l'article « Memory in .NET » de Jon Skeet, qui dit:

Notez qu'une variable de type valeur peut jamais une valeur nulle - il aurait pas de sens, comme nul est un type de référence concept, ce qui signifie "la valeur de cette variable de type de référence n'est pas une référence à un objet à tous".

Je suis un peu confus après avoir lu cette déclaration. Alors disons que j'ai int? a = null;. Comme int est normalement un type de valeur, est-il stocké en quelque sorte dans la structure Nullable<T> dans la pile (j'ai utilisé "normalement" parce que je ne sais pas ce qui se passe avec le type de valeur quand il devient nul)? Ou quoi que ce soit d'autre arrive ici - peut-être en tas?

Répondre

67

Tout d'abord, Nullable<int> est juste un raccourci pour quelque chose comme:

struct Nullable<T> 
{ 
    bool hasValue; 
    T value; 
} 

plus tous les constructeurs, accesseurs, etc. C'est tout ce qu'il est - un int nullable est un int ordinaire plus un drapeau qui indique si l'int est nul ou non. Tout le reste est la magie du compilateur qui traite "null" comme une valeur valide; tout "null" fait avec un type Nullable vous rend une de ces structs avec l'indicateur mis à false.

Alors, maintenant que nous avons cela à l'écart, votre question est "où vont-ils en mémoire"? Ils vont au même endroit que tous les autres structs en mémoire: où le runtime et le compilateur croient être le meilleur endroit compte tenu de la durée de vie de la mémoire.

La plupart des structures vont sur le tas. Quiconque vous dit que «les structures vont toujours sur la pile» ne sait pas vraiment de quoi elles parlent; notre documentation ne dit pas cela et ce n'est pas vrai. Les structures ne vont que sur le pool de mémoire temporaire, alias "la pile", quand elles sont des variables locales ou temporaires, et les variables locales ne sont pas fermées sur les variables externes d'une méthode anonyme ou lambda, et les variables locales ne sont pas dans un itérateur bloc. Toutes les autres structures vont dans le tas dans notre implémentation.

Notez également qu'il n'y a aucune exigence qu'une implémentation de la CLI utilise "la pile" pour créer son pool temporaire. Le gestionnaire de mémoire JScript classique, par exemple, stocke son pool temporaire sur le tas. (Bien que le moteur d'exécution de JScript ne soit pas une implémentation de la CLI, je signale simplement que l'on peut concevoir un moteur d'exécution managé qui ne place aucune donnée utilisateur sur la pile.) Logiquement, il s'agit d'une structure de données , mais cette structure de données n'est pas stockée sur "la" pile, c'est juste une structure de pile allouée sur le tas.

Je dois demander: pourquoi vous en souciez-vous? Le CLR gère la mémoire en votre nom. Pourquoi vous souciez-vous des types nullables? Ils vont là où ils vivent assez longtemps pour vous être utiles; vous n'avez pas à vous en préoccuper.

+6

Un très facile +1 de moi. Merci pour votre réponse épuisante. Je m'en soucie parce que je suis curieux. Je pense (peut-être naïvement) que c'est une information précieuse pour savoir ce qui se passe réellement derrière mon code. Je ne veux pas finir par coder quelque chose qui fait la magie de Dieu-sait-quelle. –

+2

@Ondrej, si vous pensez que le support du compilateur Nullable est magique, essayez d'écrire une méthode IEnumerable avec des retours de rendement en utilisant une expression lambda contenant une fermeture. Ouvrez le programme résultant dans ildasm et jetez un oeil à ce que le compilateur a fait pour vous sous les couvertures. –

+0

Je parlais généralement. Pas que je pense réellement que tout dans la programmation est une magie. Je suis conscient qu'il y a probablement plus de morceaux de code difficiles à comprendre que cela. –

7

Voir le commentaire de Eric sur les endroits où sont stockés les structs. C'est beaucoup plus complet (et correct) que ce que j'ai posté. La façon dont cela fonctionne est que le nullable a un booléen qui indique si oui ou non la valeur a été définie. Techniquement, vous avez raison, nullable (int, bool) etc n'est pas réellement nul. il a une valeur par défaut. C'est juste que maintenant le type Nullable a un booléen, vous pouvez vérifier et voir si cette valeur a été définie ou c'est juste sa valeur par défaut. Le = et == sont remplacées pour définir les valeurs appropriées lors de l'attribution null (et une valeur) pour le

lien MSDN à Nullables

Un autre lien décrivant comment nullables travail:
http://www.markzhou.com/blog/post/2010/01/27/Why-can-assign-e2809cnulle2809d-to-nullable-types.aspx

+4

Les structs ne sont pas toujours stockés sur la pile. Une instruction correcte est "les variables locales de type struct qui ne sont pas des variables externes fermées d'une méthode anonyme ou des expressions lambda et qui ne sont pas dans un bloc d'itérateur sont stockées sur la pile dans l'implémentation Microsoft du CLR du bureau." Il n'y a aucune exigence qu'il y ait une structure de données appelée "la pile" ou que toutes les structures soient stockées dessus. Les structs qui sont des champs d'une classe ou des sections locales dans un bloc d'itération ou des variables externes sont stockés sur le tas. –

+0

Comme toujours, merci pour la clarification. – kemiller2002

2

En plus de La réponse de Kevin: le compilateur connaît les types Nullable et change ==null en un appel à ".HasValue".

3

Nullables font seulement semblant nulle:

int? a = null; 
Debug.Assert((a == null) == (!a.HasValue)); 

Le compilateur est complice de cette mascarade. Une conséquence drôle de c'est la suivante:

Nullable<double> b = new Nullable<double>(); 
Debug.Assert(b == null); //I'm null upon construction! 

Ils ont également obtenir le soutien de la boxe spéciale:

int? c = null; 
Object d = c; 
Debug.Assert(d == null); 
Debug.Assert(!c.HasValue); 
+0

Vous avez oublié le plus magique de tous (celui que vous ne pouvez pas émuler avec une surcharge de l'opérateur): le levage de l'opérateur. –

Questions connexes