Question

Lorsque vous avez besoin de très petits objets, dites que ceux-ci contiennent 2 propriétés float et que vous en aurez des millions qui ne seront pas "détruits". tout de suite, les structs sont-ils un meilleur choix ou des classes?

Comme dans xna en tant que bibliothèque, il existe des points3, etc. en tant que structures, mais si vous devez conserver ces valeurs pendant longtemps, cela constituerait-il une menace pour les performances?

Était-ce utile?

La solution

Contrairement à la plupart des questions sur les structures, cela semble en fait être un bon usage d’une structure. Si les données qu'il contient sont des types valeur et que vous allez en utiliser beaucoup, une structure fonctionnerait bien.

Quelques conseils:

:: La structure ne doit pas dépasser 16 octets, sinon vous perdez les avantages en termes de performances.

:: Rendre la structure immuable. Cela rend l'utilisation plus claire.

Exemple:

public struct Point3D {

   public float X { get; private set; }
   public float Y { get; private set; }
   public float Z { get; private set; }

   public Point3D(float x, float y, float z) {
      X = x;
      Y = y;
      Z = z;
   }

   public Point3D Invert() {
      return new Point3D(-X, -Y, -Z);
   }

}

Autres conseils

La réponse dépend du lieu où les objets / valeurs seront éventuellement stockés. S'ils doivent être stockés dans une collection non typée comme ArrayList, vous finissez par les mettre en boîte. Boxing crée un wrapper d'objet pour une structure et l'empreinte est identique à celle d'un objet de classe. D'autre part, si vous utilisez un tableau typé comme T [] ou List, alors l'utilisation de struct ne stockera que les données réelles de chaque élément avec une empreinte pour la collection entière uniquement et non ses éléments.

Les structures sont donc plus efficaces dans les tableaux T [].

La grande préoccupation est de savoir si la mémoire est allouée sur la pile ou sur le tas. Les structures vont dans la pile par défaut, et la pile est généralement beaucoup plus limitée en termes d'espace. Donc, créer tout un tas de structures comme ça peut être un problème.

En pratique, cependant, je ne pense pas que ce soit un gros problème. Si vous en avez autant, ils font probablement partie d'une instance de classe (sur le tas) quelque part.

Struct semble convenir à cette application.

N'oubliez pas que le "besoin de conserver ces valeurs" implique leur stockage sur le tas quelque part, probablement un champ de tableau d’une instance de classe.

Une chose à surveiller est que cela se traduit par une allocation sur le gros tas d'objets. Ce n’est pas clair comment ce tas se défragment, s’il en est, mais pour des objets très anciens qui ne sont peut-être pas un problème.

L'utilisation de la classe pour des millions de ces types de données coûterait probablement très cher en cas de déréférencement des opérations de déréférencement pour les opérations de ce type.

En règle générale, il est préférable de stocker dans de grandes structures de données de même type (c'est-à-dire non partagées) du même type, sans alias (par exemple), car les performances sont réduites, car vous réduisez le nombre des indirections. (Voir aussi when-are-structs-the-answer ). La différence de performance exacte entre class et struct dépend de votre utilisation. (Par exemple, dans les opérations, n’accédez-vous qu’à des parties de la structure? Faites-vous beaucoup de copies temporaires? Si la structure est petite, il est probablement toujours préférable de l’utiliser, mais si elle est volumineuse, la création de copies temporaires risque de vous ralentir. rendez-le immuable, vous devrez toujours copier le tout pour changer la valeur.)

En cas de doute, mesurez.

Puisque vous êtes intéressé par les effets à long terme possibles qui pourraient ne pas être évidents grâce à une telle mesure, sachez que de tels tableaux sont probablement stockés sur le tas d'objet volumineux et doivent être réutilisés au lieu d'être détruits et réaffectés. . (voir CRL vers l’intérieur: tas de objets non couverts .)

Lorsque vous passez des structures de plus grande taille dans les appels, vous pouvez les transmettre avec l'argument ref pour éviter toute copie.

Les types de valeur (struct) conviennent aux types qui ne sont pas souvent alloués sur le tas, c'est-à-dire qu'ils sont généralement contenus dans un autre type de référence ou de valeur.

L’exemple Vector3 que vous avez donné est un exemple parfait. Vous aurez rarement un vecteur suspendu dans le tas, il sera la plupart du temps contenu dans un type qui est lui-même dans le tas ou utilisé comme variable locale, auquel cas il sera alloué sur la pile.

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