Devez-vous définir tous les objets sur null
( Nothing
dans VB.NET) une fois que vous en avez terminé avec eux?
Je comprends que dans .NET, il est essentiel de disposer de toutes les instances d'objets qui implémentent l' IDisposable
interface pour libérer certaines ressources bien que l'objet puisse toujours être quelque chose après avoir été éliminé (d'où la isDisposed
propriété dans les formulaires), donc je suppose qu'il peut toujours résider en mémoire ou du moins en partie?
Je sais aussi que lorsqu'un objet sort du champ d'application, il est alors marqué pour la collecte prêt pour le prochain passage du garbage collector (bien que cela puisse prendre du temps).
Donc, avec cela à l'esprit, le paramétrer pour null
accélérer le système libérant la mémoire car il n'a pas à déterminer qu'il n'est plus dans la portée et y a-t-il des effets secondaires négatifs?
Les articles MSDN ne le font jamais dans les exemples et actuellement je le fais car je ne vois pas le mal. Cependant, j'ai rencontré un mélange d'opinions, donc tous les commentaires sont utiles.
Réponses:
Karl est tout à fait correct, il n'est pas nécessaire de définir les objets sur null après utilisation. Si un objet est implémenté
IDisposable
, assurez-vous simplement d'appelerIDisposable.Dispose()
lorsque vous avez terminé avec cet objet (enveloppé dans un bloctry
..finally
ou, unusing()
bloc). Mais même si vous ne vous souvenez pas d'appelerDispose()
, la méthode finaliser sur l'objet devrait vous appelerDispose()
.J'ai pensé que c'était un bon traitement:
et ça
Il ne sert à rien d'essayer de remettre en question le GC et ses stratégies de gestion parce qu'il est auto-ajustable et opaque. Il y a eu une bonne discussion sur le fonctionnement interne avec Jeffrey Richter sur Dot Net Rocks ici: Jeffrey Richter sur le modèle de mémoire Windows et le livre Richters CLR via C # chapitre 20 a un excellent traitement:
la source
Une autre raison d'éviter de définir des objets sur null lorsque vous en avez terminé avec eux est que cela peut en fait les garder en vie plus longtemps.
par exemple
permettra à l'objet référencé par someType d'être GC après l'appel à "DoSomething" mais
peut parfois garder l'objet en vie jusqu'à la fin de la méthode. Le JIT optimisera généralement l'assignation à null , de sorte que les deux bits de code finissent par être identiques.
la source
GC.KeepAlive(someType);
See ericlippert.com/2013/06/10/construction-destructionNon, n'annulez pas les objets. Vous pouvez consulter http://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspx pour plus d'informations, mais en définissant les choses à null ne fera rien, sauf salir votre code.
la source
Aussi:
la source
En général, il n'est pas nécessaire d'annuler les objets après utilisation, mais dans certains cas, je trouve que c'est une bonne pratique.
Si un objet implémente IDisposable et est stocké dans un champ, je pense qu'il est bon de l'annuler, juste pour éviter d'utiliser l'objet supprimé. Les bogues du type suivant peuvent être douloureux:
Il est bon d'annuler le champ après l'avoir supprimé et d'obtenir un NullPtrEx juste à la ligne où le champ est à nouveau utilisé. Sinon, vous pourriez rencontrer un bug cryptique sur toute la ligne (en fonction de ce que fait exactement DoSomething).
la source
.Dispose()
. Si vous le trouvez, vous n'utilisez pas correctement IDisposable. La seule utilisation d'un objet jetable doit être dans les limites d'un bloc d'utilisation. Et après le bloc d'utilisation, vous n'y avez même plus accèsmyField
. Et dans le bloc using, le réglage surnull
n'est pas obligatoire, le bloc using supprimera l'objet pour vous.Il y a de fortes chances que votre code ne soit pas suffisamment structuré si vous ressentez le besoin de
null
variables.Il existe plusieurs façons de limiter la portée d'une variable:
Comme mentionné par Steve Tranby
De même, vous pouvez simplement utiliser des accolades:
Je trouve que l'utilisation d'accolades sans aucun "titre" pour vraiment nettoyer le code et aider à le rendre plus compréhensible.
la source
Le seul moment où vous devez définir une variable sur null est lorsque la variable ne sort pas du champ d'application et que vous n'avez plus besoin des données qui lui sont associées. Sinon, il n'y a pas besoin.
la source
En général, pas besoin de définir sur null. Mais supposons que vous ayez une fonctionnalité de réinitialisation dans votre classe.
Ensuite, vous pouvez le faire, car vous ne souhaitez pas appeler dispose deux fois, car une partie de Dispose peut ne pas être implémentée correctement et lever l'exception System.ObjectDisposed.
la source
ce type de "il n'est pas nécessaire de définir des objets à null après utilisation" n'est pas entièrement précis. Vous devez parfois NULL la variable après l'avoir supprimée.
Oui, vous devriez TOUJOURS appeler
.Dispose()
ou.Close()
sur tout ce qui l'a lorsque vous avez terminé. Qu'il s'agisse de descripteurs de fichiers, de connexions de bases de données ou d'objets jetables.Le modèle très pratique de LazyLoad est séparé de cela.
Dites que j'ai et instancié
ObjA
declass A
.Class A
a une propriété publique appeléePropB
declass B
.En interne,
PropB
utilise la variable privée de_B
et par défaut à null. QuandPropB.Get()
est utilisé, il vérifie si_PropB
est nul et si c'est le cas, ouvre les ressources nécessaires pour instancier unB
dans_PropB
. Il revient ensuite_PropB
.D'après mon expérience, c'est une astuce vraiment utile.
Là où le besoin de null entre en jeu, c'est si vous réinitialisez ou modifiez A d'une manière dont le contenu de
_PropB
était l'enfant des valeurs précédentes deA
, vous devrez Dispose AND null out_PropB
afin que LazyLoad puisse réinitialiser pour récupérer la bonne valeur SI le code l'exige.Si vous ne le faites
_PropB.Dispose()
et que peu de temps après, vous vous attendez à ce que la vérification null pour LazyLoad réussisse, elle ne sera pas nulle et vous examinerez des données périmées. En effet, vous devez l'annuler aprèsDispose()
juste pour être sûr.J'aurais bien aimé qu'il en soit autrement, mais j'ai actuellement du code présentant ce comportement après un
Dispose()
sur un_PropB
et en dehors de la fonction d'appel qui a fait le Dispose (et donc presque hors de portée), le prop privé n'est toujours pas nul, et les données périmées sont toujours là.Finalement, la propriété supprimée sera annulée, mais cela n'a pas été déterministe de mon point de vue.
La raison principale, comme dbkk y fait allusion, est que le conteneur parent (
ObjA
avecPropB
) garde l'instance de_PropB
dans la portée, malgré leDispose()
.la source
Dans certains cas, il est logique d'utiliser des références nulles. Par exemple, lorsque vous écrivez une collection - comme une file d'attente prioritaire - et par votre contrat, vous ne devriez pas garder ces objets en vie pour le client après que le client les a supprimés de la file d'attente.
Mais ce genre de chose n'a d'importance que dans les collections de longue date. Si la file d'attente ne survivra pas à la fin de la fonction dans laquelle elle a été créée, cela importe beaucoup moins.
Dans l'ensemble, vous ne devriez vraiment pas vous inquiéter. Laissez le compilateur et GC faire leur travail pour que vous puissiez faire le vôtre.
la source
Jetez également un œil à cet article: http://www.codeproject.com/KB/cs/idisposable.aspx
Pour la plupart, la définition d'un objet sur null n'a aucun effet. La seule fois où vous devez vous assurer de le faire, c'est si vous travaillez avec un "gros objet", dont la taille est supérieure à 84 Ko (comme les bitmaps).
la source
Stephen Cleary explique très bien dans cet article: Dois-je définir des variables sur Null pour aider le nettoyage de la mémoire?
Dit:
La chose importante à considérer est les champs statiques .
Conclusion:
la source
Je crois que de par la conception des implémenteurs GC, vous ne pouvez pas accélérer GC avec l'annulation. Je suis sûr qu'ils préféreraient que vous ne vous inquiétiez pas de comment / quand GC fonctionne - traitez-le comme cet être omniprésent protège et veille sur vous ... (s'incline la tête en bas, lève le poing vers le ciel) .. .
Personnellement, je mets souvent explicitement des variables à null lorsque j'en ai fini avec elles comme une forme d'auto-documentation. Je ne déclare pas, n'utilise pas, puis ne mets pas à null plus tard - je null immédiatement après qu'ils ne soient plus nécessaires. Je dis, explicitement, "J'en ai officiellement fini avec toi ... sois parti ..."
L'annulation est-elle nécessaire dans une langue du GC? Non. Est-ce utile pour le GC? Peut-être que oui, peut-être non, je ne sais pas avec certitude, de par sa conception, je ne peux vraiment pas le contrôler, et quelle que soit la réponse d'aujourd'hui avec cette version ou celle, les futures implémentations de GC pourraient changer la réponse hors de mon contrôle. De plus, si / quand l'annulation est optimisée, ce n'est guère plus qu'un commentaire sophistiqué si vous voulez.
Je pense que si cela rend mon intention plus claire pour le prochain pauvre imbécile qui suit mes traces, et si cela «pourrait» potentiellement aider GC parfois, alors cela en vaut la peine pour moi. Surtout, cela me fait me sentir bien rangé et clair, et Mongo aime se sentir bien rangé et clair. :)
Je le regarde comme ceci: les langages de programmation existent pour permettre aux gens de donner à d'autres personnes une idée de l'intention et au compilateur une demande de travail sur ce qu'il faut faire - le compilateur convertit cette demande dans un langage différent (parfois plusieurs) pour un processeur - le (s) CPU (s) pourrait (s) donner une idée de la langue que vous avez utilisée, des paramètres de votre onglet, des commentaires, des accents stylistiques, des noms de variables, etc. Beaucoup de choses écrites dans le code ne sont pas converties en ce qui est consommé par le processeur dans l'ordre que nous avons spécifié. Notre C, C ++, C #, Lisp, Babel, assembleur ou tout ce qui est de la théorie plutôt que de la réalité, écrit comme un énoncé de travail. Ce que vous voyez n'est pas ce que vous obtenez, oui, même en langage assembleur.
Je comprends que l'état d'esprit des «choses inutiles» (comme les lignes vides) «ne sont rien d'autre que du bruit et du code encombrant». C'était moi plus tôt dans ma carrière; Je comprends totalement cela. À ce stade, je me penche vers ce qui rend le code plus clair. Ce n'est pas comme si j'ajoutais même 50 lignes de «bruit» à mes programmes - c'est quelques lignes ici ou là.
Il existe des exceptions à toute règle. Dans les scénarios avec mémoire volatile, mémoire statique, conditions de course, singletons, utilisation de données "périmées" et tout ce genre de pourriture, c'est différent: vous DEVEZ gérer votre propre mémoire, en verrouillant et en annulant à propos car la mémoire ne fait pas partie de l'univers GC'd - j'espère que tout le monde comprend cela. Le reste du temps, avec les langages GC, c'est une question de style plutôt que de nécessité ou une amélioration garantie des performances.
À la fin de la journée, assurez-vous de comprendre ce qui est éligible pour GC et ce qui ne l'est pas; verrouiller, éliminer et annuler de manière appropriée; cirer, cirer; Inspire, expire; et pour tout le reste je dis: si ça fait du bien, fais-le. Votre kilométrage peut varier ... comme il se doit ...
la source
Je pense que remettre quelque chose à zéro est compliqué. Imaginez un scénario où l'élément défini sur now est exposé, par exemple, via une propriété. Maintenant, si un morceau de code utilise accidentellement cette propriété après la suppression de l'élément, vous obtiendrez une exception de référence nulle qui nécessite une enquête pour déterminer exactement ce qui se passe.
Je pense que les jetables de framework permettront de lancer ObjectDisposedException, ce qui est plus significatif. Ne pas les remettre à zéro serait mieux alors pour cette raison.
la source
Certains objets supposent la
.dispose()
méthode qui force la suppression de la ressource de la mémoire.la source