Question

Je sais que la boxe est un concept populaire avec de nombreuses informations, mais j'ai quelques questions auxquelles je ne trouve pas vraiment de réponses:

1) Si la boxe aboutit à la conversion d'un type de valeur (struct) en objet (type de référence) ou type de référence, pourquoi utiliser un type de valeur qui sera encadré et entraînera une pénalité de performance? Je suis conscient des avantages et de la pertinence dans certains cas d'une structure ou d'une classe. On dit (1) que les valeurs (types de valeur) ont tendance à vivre sur la pile dans un espace de stockage temporaire, mais pour combien de temps? Si je n'ai pas besoin du type, comment puis-je m'assurer qu'il est pris en charge et éliminé à ce moment-là? Ou est-ce là que le motif jetable entre en jeu? Je suppose que la raison d'utiliser une structure sera due à ses avantages.

Fait intéressant, si j'utilise une structure pour stocker deux chaînes et un champ DateTime, la structure contiendra deux références (chaînes) et la DateTime ensemble. Je suppose évidemment que cela est plus rapide que les valeurs dispersées. Y a-t-il quelque chose que je dois savoir dans cette conception? (2).

1) http: //en.csharp-online .net / Classes, structures et objets - Boxing et Unboxing

2) http://dotnetperls.com/Content/Struct-Examples.aspx

J'ai fait une recherche ici pour trouver les réponses que je cherche, mais pas de chance. Je fais habituellement des recherches sur ce site sur des sujets tels que le GC, les génériques, la gestion des exceptions, etc., car il y a beaucoup de sagesse à apprendre et à partager.

Merci pour l’éducation (potentielle) de toutes les affiches! S'il vous plaît excuser toute naïveté potentielle. Apprendre les composants internes m’amène gentiment à passer un peu de temps à comprendre la IL, etc. (quelque chose à aborder, bientôt).

Était-ce utile?

La solution

Si vous ne transmettez jamais le type de valeur à une variable de référence, la boxe ne se produira pas. Si vous ne le savez pas, répondez aux questions :

  • Agissez comme des types primitifs.
  • Avoir une taille d'instance inférieure à 16 octets.
  • sont immuables.
  • La sémantique des valeurs est souhaitable.

Je considère aussi généralement quelle est la durée de vie d’une telle variable. S'il s'agit d'une variable locale utilisée dans une méthode, j'essaierais d'utiliser struct (sinon class).

Autres conseils

Vous devez utiliser les types de valeur en raison de leur avantage logique, et non des gains de performance. Cela dit, étant donné que les types de valeur sont gérés sur la pile, il n'est pas nécessaire de participer à la récupération de place. Si vous avez un type qui est constamment créé et ignoré (comme un int, float, double, etc.), vous pouvez obtenir un bon boost en le transformant en struct. La chose à faire est que vous ne devriez vraiment considérer cela que si vous pouvez également rendre la structure immuable.

Quelques autres points à prendre en compte -

Tout d'abord, vous voulez vous assurer que les structures sont immuables (en général). Pour cette raison, c'est une bonne règle de ne pas avoir de structures contenant des types de référence. Les chaînes peuvent être une exception car elles sont immuables en C #, mais en ce qui concerne la règle générale pour la conception, je me méfierais de cela.

Deuxièmement, il y a un autre cas d'utilisation des structures qui n'a pas été mentionné jusqu'à présent: un grand nombre de petits objets. Si vous avez une longue liste ou un grand nombre de petits objets, les structures fournissent une cohérence de cache nettement meilleure et sont absolument essentielles. C’est pourquoi la plupart des moteurs 3D utilisent des structures pour les points / vecteurs - ils ont tendance à avoir de grands tableaux de points pour les sommets, etc.

C’est quelque chose qui mérite l’attention si le rendement est une partie importante de votre application. Par exemple, dans l'une de mes applications, le passage d'un type unique d'une classe à une structure permettait de gagner 40% de réduction sur un processus long (> 5 minutes). Avoir des objets rapprochés en mémoire si vous les utilisez de manière répétée dans des calculs mathématiques lourds peut générer des gains énormes.

Maintenant - dans votre cas, le fait d’avoir 2 chaînes et un DateTime ne verra probablement aucune amélioration. Les types de routines qui fonctionneraient sur les chaînes ne font probablement pas un calcul lourd (espérons-le), c’est-à-dire: transformer un demi-million de points dans l’espace, faire une grande solution matricielle, etc.

.

Enfin, vous remarquerez que .net3.5sp1 a rendu les structs beaucoup plus utiles. Avant 3.5sp1 (sur x86), il n'y avait pas d'inline de méthodes avec des appels de structure. Cela limitait les gains de performances possibles via les structures. La mise à jour de votre infrastructure peut rendre l’ancien code structuré beaucoup plus rapide (dans certains cas).

Vous n’avez pas toujours besoin de la boxe et les génériques n’ont guère besoin de ça.
La mémoire utilisée par les types de valeur (struct est un type de valeur) sera revendiquée comme

dès que la méthode se termine / revient et que vous n'avez pas besoin de faire quoi que ce soit pour que cela se produise.

Les types de valeur déclarés en tant que membres d'instance seront en mémoire jusqu'à ce que l'objet

est supprimé par le GC.

Les types de référence sont conservés sur le tas géré.
Les types de référence instanciés dans une méthode seront supprimés par le fichier
garbage collector quand aucun objet ne contient de référence.

GC fonctionne tout seul et vous devez généralement le laisser tranquille.
Vous ne pouvez pas prédire quand un objet va être supprimé par le GC.

Le modèle Dispose est utilisé sur les types de référence mais ne forcera pas le GC à supprimer
un objet. Il est généralement utilisé pour libérer des ressources non gérées.

Pour les valeurs de la pile, tenez compte des éléments suivants:
Disons que vous avez un programme simple avec trois méthodes, comme ci-dessous:
Lorsque ce programme est exécuté, la méthode Main est exécutée, etc. S'il vous plaît suivez le
numéros ci-dessous:


Main
{
   // (0) Stack is empty
   int firstInt = 0;
   // (1) Stack now contains:
   //                     firstInt
   DoSomething1();
   // (7) Stack still contains:
   //                     firstInt
}
// Program ends

DoSomething()
{
   int anInteger = 0; 
   // (2) Stack now contains:
   //                    anInteger
   //                    firstInt
   DoMore()
   // (5) Stack now contains:
   //                     anInteger
   //                     firstInt
}
// (6) anInteger goes out of scope

DoMore
{
  int anotherInteger = 1; 
   // (3) Stack now contains:
   //                     anotherInteger
   //                     anInteger
   //                     firstInt
}
// (4) anotherInteger goes out of scope

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