12
votes

C # - Les objets sont-ils immédiatement détruits lorsqu'ils sont hors de portée?

Puis-je faire confiance à qu'un objet est détruit et son destructeur est appelé immédiatement lorsqu'il sort de la portée en C #?

Je pense que cela devrait que de nombreuses pratiques de codage communes (par exemple, des objets de transaction) reposent sur ce comportement, mais je ne suis pas très habitué à travailler avec la collecte des ordures et à avoir peu de perspectives à la manière dont ces langues se comportent habituellement.

merci.


1 commentaires

@ R.A - Désolé pour le retard, certaines tâches d'IRL ont fait de :) Ajout de quelques exemples maintenant, j'espère que cela clarifie encore plus loin.


6 Réponses :


32
votes

Nope, .NET et donc c # s'appuie sur une gestion de la mémoire de collecte des ordures. Les extronseurs (qui sont en .NET sont appelés finaliseurs) ne sont pas appelés que GC ne le trouve appropriée pour détruire les objets.

En outre: la plupart des objets "réguliers" dans C # ne sont pas destructeurs. Si vous avez besoin du motif destructeur, vous devez implémenter le interface Idisposable avec Disposez le modèle . Sur des objets jetables, vous devez également vous assurer que la méthode de disposer est appelée, soit avec le Mot-clé ou appelant directement la méthode. P>

Pour plus loin (espérons-le) clarifier: l'élimination déterministe est utile dans .NET par exemple. Lorsque vous devez explicitement libérer des ressources qui ne sont pas gérées par le .NET Runtime. Des exemples de telles ressources sont des poignées de fichier, des connexions de base de données, etc. Il est généralement important que ces ressources soient libérées dès qu'ils ne sont plus nécessaires. Nous ne pouvons donc pas nous permettre d'attendre que le GC leur libère. P>

Pour obtenir une élimination déterministe (semblable au comportement de la portée de C ++) dans le monde non déterministe du .NET GC, le .NET Les classes s'appuient sur l'interface Idisposable. Emprunter à partir du Dispose modèle , voici quelques exemples: p>

Premier, instanciation Une ressource jetable puis laisser tomber l'objet hors de portée, laissera jusqu'à GC afin de disposer de l'objet: p> xxx pré>

pour résoudre ce problème, nous pouvons explicitement disposer de l'objet: P>

1.    using (var dr = new DisposableResource())
2.    {
3.       ...
4.    }


5 commentaires

L'asker de la question ne connaît pas les subtilités de ce qu'un destructeur C # est, alors je ne pense pas que vous devriez simplement appeler un destructeur un finisseur et être fait avec elle. C ++ Destructeurs et C # Destructeurs sont choses très différentes.


N'oubliez pas non plus que la collection de poubelles .NET est basée sur une "génération". Un objet peut donc potentiellement être des ordures collectées par une collection de génération 0, mais n'a pas été complètement "détruite" ou "retirée" de la mémoire. Pensez également à de telles choses que de faibles références dans lesquelles un objet peut être recruté, mais toujours accessible par le code de votre application! Fondamentalement, un objet durera tant que le temps d'exécution le souhaite. Vous n'avez pas de dire en la matière! ;) ( Simple-Talk. COM / DotNet / .NET-Framework / ... )


@Peter: Merci pour votre réponse. Suggérez-vous que Idisposable offre un moyen d'atteindre le comportement de portée observé dans l'exemple C ++? Voulez-vous envisager de l'élaborer et peut-être ajouter du code?


Disposer pas la destruction déterministe. Je ne peux pas souligner cela assez.


@Joren - Oui, je suppose que la destruction concerne la libération de la mémoire. Je veux vraiment dire "élimination déterministe" et avoir reformulé ainsi.



0
votes

Je ne pense pas que vous devriez compter sur les collectionneurs à déchets de cette manière. Même si vous déduisez comment ils fonctionnent, cela pourrait très bien être que dans la prochaine version, ils l'ont réimplanté.

Dans tous les cas, les objets ne sont pas des ordures collectées au moment où vous les ingérez. Typiquement, ils sont collectés jusqu'à ce que certains seuils soient atteints, puis ils sont libérés.

Surtout dans les programmes Java, cela est très perceptible lorsque vous examinez la consommation de mémoire sur le gestionnaire de tâches. Il pousse et pousse et tout soudain chaque minute qu'il tombe à nouveau.


0 commentaires

4
votes

Il n'y a pas de telle chose SLA A C ++ - comme destructeur de type C #. (Il existe un concept différent de destructeur en C #, également appelé finaliseur, qui utilise la même syntaxe que C ++ Destructeurs, mais ils ne sont pas liés à la destruction d'objets. Ils sont destinés à fournir un mécanisme de nettoyage pour des ressources non gérées.) Le collecteur des ordures va nettoyer des objets un jour après qu'ils ne soient plus référencés . Pas immédiatement, et il n'y a aucun moyen de garantir cela non plus.

Heureusement, il n'y a pas non plus de vraie raison pour laquelle vous voudriez vous garantir cela. Si vous avez besoin de la mémoire, le GC la récupérera alors. Si vous ne le faites pas, pourquoi se soucier s'il y a encore un objet ordures autour? Ce n'est pas une fuite de mémoire: le GC peut toujours le trouver et la nettoyer à tout moment.


0 commentaires

4
votes

Non, ce n'est pas garanti. Semblable aux langues telles que Java, en C #, le collecteur des ordures s'exécute quand il est nécessaire (i. E. Quand le tas devient trop complet). Cependant, lorsque vos objets impliquent Idisposable , i. e. ils ont un Dispose () méthode et il faut appeler, alors vous pouvez tirer parti de la à l'aide du mot-clé : xxx

que Way Dispose () sera appelé immédiatement lors de la sortie de ce à l'aide du bloc .

Remarque: Idisposable est trouvé dans de nombreux types , plus notamment les connexions, les transactions, etc. de GDI + mais aussi de la base de données, donc il peut vraiment être le bon modèle ici.

Note 2: Dans les coulisses ci-dessus, le bloc sera traduit dans un Essayez / enfin bloc: xxx

mais cette traduction est effectuée par le compilateur et très pratique pour n'oublier pas d'appeler Disposer () < / code>.


0 commentaires

0
votes

Non. Si vous vous référez à la spécification CLI (p. 8.9.6.7 sur les finaliseurs) http://www.ecma-international.org/publications/files/ecma-st/ecma-335.pdf Vous pouvez trouver ce qui suit

Le CLI devrait S'assurer que les finaliseurs sont appelés peu de temps après que l'instance devienne inaccessible. Tout en s'appuyant sur la pression de la mémoire La finalisation de la gâchette est acceptable, les impléments doivent envisager l'utilisation de Metrics

Mais cela ne doit pas.


0 commentaires

12
votes

Non. Un objet ne va pas réellement "hors de portée", la référence à celle-ci (c'est-à-dire la variable que vous utilisez pour y accéder).

Une fois qu'il n'y a plus de références à un objet donné, Cet objet devient éligible pour la collecte des ordures (GC) si le besoin se pose. Chaque fois que le GC décide qu'il doit récupérer l'espace votre objet non référencé, c'est lorsque le finaliseur des objets sera appelé.

Si votre objet est une ressource (par exemple, une poignée de fichier, une connexion de base de données), Il devrait mettre en œuvre l'interface Idisposable (qui oblige l'objet à implémenter un Dispose () méthode pour nettoyer toutes les connexions ouvertes, etc.). La meilleure pratique pour vous dans ce cas serait de créer l'objet dans le cadre d'un bloc en utilisant le bloc , de sorte que lorsque ce bloc est terminé, votre application appelle automatiquement les objets Dispose () < / Code> Méthode, qui prendra soin de la fermeture de votre connexion de fichier / dB / autre.

par exemple par exemple xxx

le en utilisant Le bloc est juste un peu de sucre syntaxique qui enveloppe vos interactions avec l'objet conn dans un Essayez Block, ainsi qu'un bloc enfin bloc qui appelle uniquement < code> conn.dispose ()


0 commentaires