Quelles sont les conséquences (positives/négatives) de l'utilisation de la non sécurisé mot-clé dans C# d'utiliser des pointeurs ? Par exemple, que devient le garbage collection, quels sont les gains/pertes de performance, quels sont les gains/pertes de performance par rapport à la gestion manuelle de la mémoire d'autres langages, quels sont les dangers, dans quelle situation est-il vraiment justifié d'utiliser cette caractéristique du langage, est-ce plus long à compiler... ?
Réponses
Trop de publicités?Comme l'a déjà mentionné Conrad, il existe certaines situations où l'accès non sécurisé à la mémoire en C# est utile. Il n'y a pas comme beaucoup d'entre eux, mais il y en a :
-
Manipuler avec
Bitmap
est presque un exemple typique où vous avez besoin d'une performance supplémentaire que vous pouvez obtenir en utilisantunsafe
. -
Interopérabilité avec des API plus anciennes (telles que WinAPI ou les DLL natives de C/C++) est un autre domaine dans lequel
unsafe
peut être très utile - par exemple, vous pouvez vouloir appeler une fonction qui prend/retourne un pointeur non géré.
D'autre part, vous pouvez écrire la plupart des choses en utilisant Marshall
classe qui dissimule un grand nombre d'opérations non sécurisées dans des appels de méthode. Cette méthode sera un peu plus lente, mais c'est une option si vous voulez éviter d'utiliser la fonction unsafe
(ou si vous utilisez VB.NET, qui ne dispose pas de la fonction unsafe
)
Conséquences positives : Ainsi, les principales conséquences positives de l'existence des unsafe
en C# est que vous pouvez écrire du code plus facilement (interopérabilité) et vous pouvez écrire du code plus efficacement (manipulation de bitmap ou peut-être quelques calculs numériques lourds en utilisant des tableaux - bien que, je ne sois pas si sûr de la deuxième).
Conséquences négatives : Bien sûr, il y a un certain prix à payer pour utiliser unsafe
:
-
Code non vérifiable : Le code C# qui est écrit en utilisant le
unsafe
devient invérifiable, ce qui signifie que votre code pourrait compromettre le runtime de quelque manière que ce soit. Ce n'est pas un gros problème dans un confiance totale (par exemple, une application de bureau non restreinte) - vous ne bénéficiez pas de toutes les garanties du CLR de .NET. Cependant, vous ne pouvez pas exécuter l'application dans un environnement restreint tel qu'un hébergement Web public, Silverlight ou une confiance partielle (par exemple, une application exécutée à partir du réseau). -
Collecteur d'ordures doit également faire attention lorsque vous utilisez
unsafe
. GC est généralement autorisé à relocaliser des objets sur le tas géré (pour que la mémoire reste défragmentée). Lorsque vous prenez un pointeur sur un objet, vous devez utiliser l'attributfixed
pour indiquer à la GC qu'elle ne peut pas déplacer l'objet tant que vous n'avez pas terminé (ce qui pourrait probablement affecter les performances de la collecte des déchets - mais bien sûr, cela dépend du scénario exact).
Je pense que si C# n'avait pas à interopérer avec du code plus ancien, il ne supporterait probablement pas unsafe
(et des projets de recherche comme Singularity qui tentent de créer des systèmes d'exploitation plus vérifiables basés sur des langages gérés interdisent définitivement le code usnsafe). Cependant, dans le monde réel, unsafe
est utile dans certains (rares) cas.
Je peux vous donner une situation où ça valait la peine de l'utiliser :
Je dois générer un bitmap pixel par pixel. Drawing.Bitmap.SetPixel()
est bien trop lent. J'ai donc construit mon propre système de gestion Array
de données bitmap, et utiliser unsafe
pour obtenir le IntPtr
para Bitmap.Bitmap( Int32, Int32, Int32, PixelFormat, IntPtr)
.
Pour citer Professional C# 2008 :
"Les deux principales raisons d'utiliser les pointeurs sont :
- Compatibilité ascendante - Malgré toutes les facilités offertes par le .NET, il est toujours possible de d'appeler des fonctions natives de l'API Windows, et pour certaines opérations, cela peut être la seule façon d'accomplir votre tâche. Ces fonctions API sont généralement écrites en C et nécessitent souvent des pointeurs comme paramètres. Cependant, en Toutefois, dans de nombreux cas, il est possible d'écrire la déclaration déclaration DllImport d'une manière qui éviter l'utilisation de pointeurs, par exemple, en utilisant la classe System.IntPtr.
- Performance - Dans les cas où la rapidité est de la plus haute importance, un importance, le pointeur peut fournir un une voie vers des performances optimisées. Si vous savez ce que vous faites, vous pouvez s'assurer que les données sont accédées ou manipulées de la manière la plus efficace possible. Cependant, il faut savoir que, le plus souvent souvent, il existe d'autres domaines de votre code où vous pouvez apporter des améliorations performances nécessaires sans sans avoir recours aux pointeurs. Essayez d'utiliser un profileur de code pour rechercher les goulots d'étranglement goulots d'étranglement dans votre code - un profileur est fourni avec Visual Studio 2008".
Et si vous utilisez un pointeur, votre code nécessitera un levier de confiance plus élevé pour s'exécuter et si l'utilisateur ne l'accorde pas, votre code ne s'exécutera pas.
Et terminez par une dernière citation :
"Nous déconseillons fortement l'utilisation inutilement des pointeurs car cela non seulement plus difficile à écrire et à déboguer, mais elle échouera également aux contrôles de de la sécurité de type de la mémoire imposée par le CLR".
Le ramassage des ordures est inefficace avec les objets à longue durée de vie. Le ramasseur d'ordures de .Net fonctionne mieux lorsque la plupart des objets sont libérés assez rapidement, et que certains objets "vivent éternellement". Le problème est que les objets à longue durée de vie ne sont libérés que lors des collectes complètes, ce qui entraîne une pénalité de performance significative. En fait, les objets à longue durée de vie passent rapidement en génération 2.
(Pour plus d'informations, vous pouvez vous renseigner sur le collecteur d'ordures générationnel de .Net : http://msdn.microsoft.com/en-us/library/ms973837.aspx )
Dans les situations où les objets, ou l'utilisation de la mémoire en général, ont une longue durée de vie, la gestion manuelle de la mémoire permet d'obtenir de meilleures performances car elle peut être libérée dans le système sans nécessiter une collecte complète des déchets.
La mise en œuvre d'une sorte de système de gestion de la mémoire basé sur un seul grand tableau d'octets, des structures et beaucoup d'arithmétique de pointeurs, pourrait théoriquement augmenter les performances dans les situations où les données seront stockées dans la RAM pendant une longue période.
Malheureusement, je n'ai pas connaissance d'un bon moyen de gérer manuellement la mémoire en .Net pour les objets qui vont avoir une longue durée de vie. Cela signifie essentiellement que les applications qui ont des données à longue durée de vie dans la mémoire vive ne répondront plus à l'appel lorsqu'elles effectueront un ramassage complet de toute la mémoire.