Ne unboxing revenir juste un pointeur sur la valeur dans l'objet boxed sur le tas?

StackOverflow https://stackoverflow.com/questions/2978647

  •  24-10-2019
  •  | 
  •  

Question

Je cet article MSDN Magazine , l'auteur déclare (Souligné par l'auteur ):

Notez que la boxe crée toujours une nouvelle objet et des copies de la valeur unboxed les bits à l'objet. D'autre part, unboxing retourne simplement un pointeur vers les données dans un objet emballé: non copie de mémoire se produit. Cependant, il est généralement le cas que votre code provoquer les données pointées par la référence Unboxed à copier de toute façon.

Je suis confus par la phrase que je l'ai et la phrase en gras qui le suit. De tout ce que j'ai lu, y compris cette page MSDN , I » ai jamais entendu dire que unboxing juste renvoie un pointeur sur la valeur sur le tas. J'avais l'impression que unboxing entraînerait que vous ayez une variable contenant une copie de la valeur sur la pile, tout comme vous avez commencé. Après tout, si ma variable contient « un pointeur vers la valeur sur le tas », alors je n'ai pas un type de valeur, j'ai un pointeur.

Quelqu'un peut-il expliquer ce que cela veut dire? L'auteur était sur le crack? (Il y a au moins une autre erreur flagrante dans l'article). Et si cela est vrai, ce sont les cas où « votre code ramènerai les données pointées par la référence Unboxed à copier de toute façon »?

Je viens de remarquer que l'article est près de 10 ans, alors peut-être c'est quelque chose qui a changé très tôt dans la vie de .Net.

Était-ce utile?

La solution

L'article est exact. Il parle cependant de ce que vraiment continue, pas ce que les regards IL comme que le compilateur génère. Après tout, un programme .NET exécute jamais IL, il exécute le code de la machine qui est générée à partir de l'IL par le compilateur JIT.

Et l'opcode unbox génère en effet de code qui produit un pointeur sur les bits sur le tas qui représente la valeur de type de valeur. Le JIT génère un appel à une petite fonction d'aide dans le CLR nommé « JIT_Unbox ». clr \ src \ vm \ jithelpers.cpp si vous avez le code source de SSCLI20. L'objet :: fonction retourne GetData () le pointeur.

A partir de là, la valeur le plus souvent la première est copiée dans un registre CPU. Ce qui peut alors sont stockés quelque part. Il ne doit pas être la pile, il pourrait être un membre d'un objet de type de référence (le tas gc). Ou une variable statique (le tas de chargeur). Ou il pourrait être poussé sur la pile (appel de méthode). Ou le registre du processeur peut être utilisé tel quel lorsque la valeur est utilisée dans une expression.

Lors du débogage, cliquez droit sur la fenêtre de l'éditeur et choisissez « Aller à désassemblage » pour voir le code machine.

Autres conseils

L'auteur de l'article original devait se réfère à ce qui se passe en bas au niveau IL. Il existe deux opcodes unboxing: unbox et unbox.any

.

Selon MSDN, concernant unbox.any :

Lorsqu'il est appliqué à la forme d'un coffret type de valeur, l'instruction unbox.any des extraits de la valeur contenue à l'intérieur obj (de type O), et est par conséquent équivalent à unbox suivi par ldobj.

et concernant unbox:

[...] Unbox n'a pas à copier le type de valeur de l'objet. En général, il calcule simplement le adresse du type de valeur qui est déjà présent à l'intérieur de la boîte objet.

Alors, l'auteur savait ce qu'il parlait.

Ce petit fait à propos unbox permet de faire certaines optimisations astucieuses lorsque vous travaillez directement avec IL. Par exemple, si vous avez un int boxed que vous devez passer à une fonction d'accepter un int ref, vous pouvez simplement émettre un opcode unbox, et la référence à l'int sera prêt dans la pile pour que la fonction opérer. Dans ce cas, la fonction va changer le contenu réel de l'objet de la boxe, ce qui est tout à fait impossible au niveau C #. Il vous permet d'économiser de la nécessité d'allouer de l'espace pour une variable locale temporaire, Unbox l'int là, passer un arbitre à l'int à la fonction, puis créer un nouvel objet de boxe à re-box int, en écartant la vieille boîte.

Bien sûr, quand vous travaillez au niveau C #, vous ne pouvez pas faire de telles optimisations, de sorte que ce qui généralement se produire est que le code généré par le compilateur sera presque toujours copier la variable de l'objet boxed avant la prise toute utilisation ultérieure de celui-ci.

Boxing est le fait de couler une instance de type valeur à une instance de type de référence (soit un object ou une interface), et les types de référence sont attribués sur le tas.

Selon 'C # 4.0 in a Nutshell'. "... unboxing copies le contenu de l'arrière de l'objet dans une instance de valeurs de type" et cela implique sur la pile

Dans l'article que vous faites référence, l'auteur déclare:

public static void Main() {

   Int32 v = 5;    // Create an unboxed value type variable
   Object o = v;   // o refers to a boxed version of v
   v = 123;        // Changes the unboxed value to 123

   Console.WriteLine(v + ", " + (Int32) o);    // Displays "123, 5"
}

A partir de ce code, pouvez-vous deviner combien se produisent des opérations de boxe? Tu pourrais être surpris de découvrir que la réponse est trois! Analysons le code attentivement pour comprendre vraiment ce qui est en cours. Tout d'abord, un type de valeur unboxed Int32 (v) est créé et initialisé à 5. Ensuite, un type de référence d'objet (o) est créé et il veut pointer vers v. Mais les types de référence doivent toujours pointer à des objets dans le tas, donc C # généré le code propre à l'IL boîte v et stocké l'adresse de la boîte version de v o dans. Maintenant 123 est unboxed et les données référencées sont copiées dans le type de valeur unboxed v; cela n'a pas effet sur la version en boîte de v, donc la version en boîte conserve sa valeur de 5. Notez que cet exemple montre comment o est unboxed (qui renvoie un pointeur vers les données o), et puis les données en o la mémoire est copié à la valeur unboxed Type v.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top