c# - Définition des objets sur Null / Nothing après utilisation dans .NET

Translate

Devriez-vous définir tous les objets surnull (Nothingdans VB.NET) une fois que vous en avez fini avec eux?

Je comprends que dans .NET, il est essentiel de supprimer toutes les instances d'objets qui implémentent leIDisposableinterface pour libérer certaines ressources bien que l'objet puisse toujours être quelque chose après avoir été supprimé (d'où leisDisposedpropriété dans les formulaires), donc je suppose qu'il peut encore résider dans la mémoire ou au 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 définirnullaccélérer le système en libérant la mémoire car il n'a pas à déterminer qu'elle n'est plus dans la portée et y a-t-il des effets secondaires négatifs?

Les articles MSDN ne font jamais cela 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.

This question and all comments follow the "Attribution Required."

Toutes les réponses

Kev
Translate

Karl est absolument correct, il n'est pas nécessaire de définir les objets sur null après utilisation. Si un objet implémenteIDisposable, assurez-vous d'appelerIDisposable.Dispose()lorsque vous avez terminé avec cet objet (enveloppé dans untry..finally, ou, unusing()bloquer). Mais même si tu ne te souviens pas d'appelerDispose(), la méthode finaliser sur l'objet doit appelerDispose()pour vous.

J'ai pensé que c'était un bon traitement:

Creuser dans IDisposable

et ça

Comprendre IDisposable

Il ne sert à rien d'essayer de remettre en question le GC et ses stratégies de gestion car 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 Windowset livre RichtersCLR via C #le chapitre 20 a un excellent traitement:

La source
Translate

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

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is now eligible for garbage collection         

    // ... rest of method not using 'someType' ...
}

permettra à l'objet référencé par someType d'être GC après l'appel à "DoSomething" mais

void foo()
{
    var someType = new SomeType();
    someType.DoSomething();
    // someType is NOT eligible for garbage collection yet
    // because that variable is used at the end of the method         

    // ... rest of method not using 'someType' ...
    someType = null;
}

peut parfois garder l'objet en vie jusqu'à la fin de la méthode. leJIT optimisera généralement l'assignation à null, donc les deux bits de code finissent par être identiques.

La source
Translate

Non, n'annulez pas les objets. Vous pouvez vérifierhttp://codebetter.com/blogs/karlseguin/archive/2008/04/27/foundations-of-programming-pt-7-back-to-basics-memory.aspxpour plus d'informations, mais définir les choses sur null ne fera rien, sauf le sale de votre code.

La source
Translate

Également:

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of
La source
Translate

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:

this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();

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
Translate

Il y a de fortes chances que votre code ne soit pas suffisamment structuré si vous ressentez le besoin denullvariables.

Il existe plusieurs façons de limiter la portée d'une variable:

Comme mentionné parSteve Tranby

using(SomeObject object = new SomeObject()) 
{
  // do stuff with the object
}
// the object will be disposed of

De même, vous pouvez simplement utiliser des accolades:

{
    // Declare the variable and use it
    SomeObject object = new SomeObject()
}
// The variable is no longer available

Je trouve qu'utiliser des accolades sans aucun "titre" pour vraiment nettoyer le code et aider à le rendre plus compréhensible.

La source
Bob
Translate

Le seul moment où vous devez définir une variable sur null est lorsque la variable n'est pas hors de portée et que vous n'avez plus besoin des données qui lui sont associées. Sinon, il n'y a pas besoin.

La source
Translate

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 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.

private void Reset()
{
    if(_dataset != null)
    {
       _dataset.Dispose();
       _dataset = null;
    }
    //..More such member variables like oracle connection etc. _oraConnection
 }
La source
Translate

ce type de "il n'est pas nécessaire de définir des objets sur null après utilisation" n'est pas entièrement exact. 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.

Dis que j'ai et instanciéObjAdeclass A. Class Aa une propriété publique appeléePropBdeclass B.

Intérieurement,PropButilise la variable privée de_Bet par défaut à null. QuandPropB.Get()est utilisé, il vérifie si_PropBest nul et si c'est le cas, ouvre les ressources nécessaires pour instancier unBdans_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 que le contenu de_PropBétaient les enfants des valeurs précédentes deA, vous devrez supprimer ET annuler_PropBdonc LazyLoad peut réinitialiser pour récupérer la bonne valeur SI le code l'exige.

Si tu fais seulement_PropB.Dispose()et peu de temps après, attendez-vous à 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 unDispose()sur un_PropBet en dehors de la fonction appelante 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 (ObjAavecPropB) conserve l'instance de_PropBdans la portée, malgré leDispose().

La source
Translate

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
Translate

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. Le seul moment où vous devez être sûr de le faire est si vous travaillez avec un "grand objet", qui est plus grand que 84K en taille (comme les bitmaps).

La source
Translate

Stephen Cleary explique très bien dans ce post:Dois-je définir des variables sur Null pour aider le nettoyage de la mémoire?

Dit:

La réponse courte, pour l'Impatient Oui, si la variable est un champ statique, ou si vous écrivez une méthode énumérable (en utilisant yield return) ou une méthode asynchrone (en utilisant async et await). Sinon, non.

Cela signifie que dans les méthodes régulières (non énumérables et non asynchrones), vous ne définissez pas les variables locales, les paramètres de méthode ou les champs d'instance sur null.

(Même si vous implémentez IDisposable.Dispose, vous ne devez toujours pas définir les variables sur null).

La chose importante à considérer estChamps statiques.

Les champs statiques sont toujours des objets racine, donc ils sonttoujours considéré comme «vivant»par le ramasse-miettes. Si un champ statique fait référence à un objet qui n'est plus nécessaire, il doit être défini sur null afin que le garbage collector le traite comme éligible pour la collecte.

La définition de champs statiques sur null n'a pas de sens si l'ensemble du processus est en cours d'arrêt. Le tas entier est sur le point d'être récupéré à ce stade, y compris tous les objets racine.

Conclusion:

Champs statiques; C'est à peu près ça. Tout le reste est unperte de temps.

La source
Translate

Je crois que par la conception des implémenteurs GC, vous ne pouvez pasaccélérerGC avec annulation. Je suis sûr qu'ils préféreraient que vous ne vous inquiétiez pas de la manière et du moment où GC fonctionne - traitez-le comme ceciÉtantprotéger et veiller 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-là, 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, c'est un peu plus qu'une fantaisiecommentairesi 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 ça vaut le coup 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 aux autres 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) pourraient vous 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 les «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 au fur et à mesure 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
Translate

Je pense que remettre quelque chose à zéro est compliqué. Imaginez un scénario dans lequel 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 crois 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
Translate

Certains objets supposent que.dispose()méthode qui force la suppression de la ressource de la mémoire.

La source