9
votes

Comment la collecte des ordures fonctionne-t-elle sur les références d'objet?

Je suis confus au sujet du processus de collecte des ordures sur des objets.

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 


2 commentaires

La collecte des ordures n'est pas un comptage de référence.


L'ensemble de la collecte des ordures est que vous n'êtes pas obligé de vous soucier quand ou si la mémoire est libérée. En principe, sur un système avec de vastes réserves de mémoire, la collecte des ordures pourrait jamais se produire, simplement parce qu'il serait plus efficace de simplement laisser nettoyer l'application lorsque la demande est terminée.


7 Réponses :


18
votes

Dispose fait pas les ordures collectées. Vous ne pouvez pas explicitement détenir un objet particulier. Vous pouvez appeler gc.collect () qui demande que le collecteur des ordures fonctionne, mais ce n'est pas la même chose. Appeler Dispose ne "déconnecte pas" l'objet d'une variable particulière, en fait ... tandis que cette variable reste en direct (jusqu'à la dernière fois que le JIT peut détecter qu'il sera à nouveau lus. ) Il empêchera que l'objet d'être recueilli.

Un objet ne sera pas recruté jusqu'à ce qu'il ne soit plus référencé par rien. Certes, cela peut être plus tôt que vous pourriez penser dans certains cas extrêmes, mais vous avez rarement besoin de vous inquiéter de ceux-ci.

On vaut la peine de sacher que Dispose et la collecte des ordures sont des choses très différentes. Vous appelez Dispose pour libérer non géré les ressources (connexions réseau, etc.). La collecte des ordures est uniquement de libérer la mémoire. Certes, la collecte des ordures peut suivre la finalisation qui peut libérer des ressources non gérées en dernier recours, mais la plupart du temps, vous devriez être éliminé des ressources non gérées explicitement.


1 commentaires

En tant qu'additaire, vous devriez JAMAIS sur les finaliseurs, car ils ne seront jamais courus. Au mieux, ils peuvent être «Derniers stations» qui essaieront de nettoyer les ressources si le programme a oublié de les éliminer correctement correctement.



16
votes

Je peux être éteint, mais vous semblez avoir un malentendu de Disposer et la collecte des ordures. Un objet sera recueilli une fois que toutes les références sont parties, de manière non déterministe. Disposez-vous généralement se débarrasser des ressources non gérées. L'objet est donc prêt à être déposé. Dans votre premier exemple, vous avez éliminé l'objet, le rendant théoriquement inutilisable, mais il existe toujours sur le tas et vous en avez toujours une référence, à la fois A et B. Une fois ceux qui sont hors de portée, le collecteur des ordures peut récupérer cette mémoire. , mais pas toujours. Dans l'exemple 2, un bitmap A est placé sur le tas, puis vous en retournez une référence et définissez B sur cette référence. Ensuite, vous le disposez et b sort hors de portée. À ce stade, il n'existe plus de références, et il sera recruté à un moment ultérieur.


6 commentaires

Merci pour votre réponse. J'aurais dû faire ma question plus claire. Je suis conscient que en appelant (), GC ne libérera pas la mémoire immédiatement, mais il supprimera la référence à l'objet à partir de la file d'attente finalisable afin que l'objet ne se déplace pas vers la génération suivante dans le deuxième exemple, comment appelons-nous DÉPOSER sur la référence passée par la fonction immédiatement après utilisation? Si nous ne pouvons pas disposer de la référence passée par la fonction statique, elle passera à la prochaine génération et il y aura plus de retard pour libérer la ressource.


@Kishore: Lorsque vous dites, disposez de la référence, c'est très déroutant ce que vous voulez dire. La référence est un pointeur sur la pile à l'objet sur le tas, du moins dans ce cas. Vous disposez des ressources non gérées dans l'instance sur le tas.


Désolé pour la confusion. Il y a donc un moyen de supprimer ou d'effacer la référence qui est passée par la fonction de manière à ce qu'elle ne pointe pas sur l'objet sur le tas?


@Kishore: Eh bien, une fois qu'il est hors de portée, il est apparu du tas. Maintenant, B est une copie d'un qui pointe vers la même instance sur le tas. Ce que je pense que vous aimeriez faire, et corrigez-moi si je me trompe, c'est de vous assurer que l'instance est disposée dans Test1. Ce qui n'est pas possible. Mais généralement si votre classe a des objets jetables, vous pouvez la marquer isisposable, de sorte que toute personne qui utilise doit être dans la théorie appeler lorsqu'elle est terminée, et vous disposerez de choses comme Bitmap dans votre méthode de jet.


@Yuriy, vous vouliez sûrement dire "SOPPEZ DE LA SACLE Pile " Pas le tas.


@siride Vous êtes, je ne sais pas comment cela a eu lieu là-bas.



3
votes

Disposer () n'a rien à voir avec la collecte des ordures. Tout ce qu'il fait, c'est permettre la libération déterministe des ressources, mais vous devez l'appeler explicitement. L'objet que vous l'appelez ne reçoit pas les ordures recueillies lorsque vous appelez disposer (). Il sera éligible à la collecte des ordures lorsque toutes les références sont parties.


0 commentaires

5
votes

Il arrive que Raymond Chen vient d'écrire une série de postes de blogs décrivant des aspects de Collection de poubelles .NET. Cet article le plus directement concerne votre question (Quand les objets sont-ils recueillis?).


2 commentaires

J'attends avec impatience la semaine CLR chaque année :)


J'allais poster un lien, mais je me sentais un peu paresseux ce matin. Il a eu des excellents postes sur des sujets liés au GC.



1
votes

OK pour les démarreurs éliminer! = poubelle collectée. Vous pouvez appeler et ne jamais avoir la poubelle collectée, car un "objet disposé" peut toujours y avoir des références. La méthode de jet est utilisée pour "ranger" l'objet avant que le CG s'exécute (fermeture de connexion DB ouverte, ou les connexions de fichiers, etc.).

public void TestB()
{
   Bitmap B = Test1();
   B.Dispose();
} 


0 commentaires

2
votes

Beaucoup de bonnes réponses ici, mais j'aime aussi souligner que la raison pour laquelle les gens pensaient que vous aviez besoin de manière consistable, c'est qu'un GC devrait vraiment être nommé MemoryCollector ou même géréMemoryCollector. Un GC n'est pas particulièrement intelligent lorsqu'il s'agit de collecter des ressources de mémoire non gérées telles que des fichiers, des conns à DB, des transactions, des poignées Windows, etc.

Une des raisons est qu'un objet géré pourrait avoir une ressource non gérée qui prend plusieurs concerts de RAM mais à la GC, il ressemble à 8 octets ou plus.

avec des fichiers, des connecteurs DB, etc. Vous souhaitez souvent les fermer dès que possible pour libérer des ressources non gérées et éviter les problèmes de verrouillage.

Avec des poignées Windows, nous avons une affinité de fil à vous inquiéter. En tant que GC exécuté dans un fil dédié que le thread est toujours le mauvais fil pour libérer des poignées de fenêtres.

SO GC aide beaucoup à éviter de fuir la mémoire gérée et à réduire l'encombrement du code, mais on devrait encore libérer des ressources non gérées dès que possible.

Utiliser () déclaration est une bénédiction.

ps. Très souvent, je m'installe idisposable même si je n'ai aucune ressource directe non gérée, ses importateursNT cependant pour informer toutes les variables des membres qui implémentent Idisposable qui disposent d'appelée.


0 commentaires

0
votes

Il peut être utile de noter que l'appelant disposer peut, en fait, ne rien faire du tout. Il donne à l'objet une chance de nettoyer des ressources telles que des connexions de base de données et des ressources non gérées. Si vous avez un objet contenant une ressource non gérée, telle qu'une connexion de base de données, Disposez indiquera à l'objet qu'il est temps de nettoyer ces références.

La question fondamentale de la collecte des ordures est: "Cet objet peut-il être atteint?" Tant qu'il existe sur l'objet sur la pile qui a une référence à votre objet (ou il y a une référence à cet objet quelque part dans la hiérarchie de l'objet), l'objet ne sera pas recruté.

Exemple:

Obja crée un Objb, qui crée un Objc. Obj c ne sera pas recueilli jusqu'à ce qu'il ne soit plus référencé par Objb ou jusqu'à ce que l'OBJB ne soit plus référencée par Obja, ou jusqu'à ce qu'il n'y ait aucun objet qui conserve une référence à OBJA.

Encore une fois, la question à poser est: "Cet objet peut-il actuellement être référencé par quelque chose dans le code?"


2 commentaires

J'aurais aussi dû mentionner que, simplement parce qu'un objet n'est pas référencé, cela ne signifie pas qu'il sera immédiatement collecté. Le collecteur des ordures prend des décisions basées sur la durée de vie d'un objet, quelle quantité de mémoire qu'il consomme et la pression de mémoire dans le système pour déterminer quoi collecter et quand. Cela prend un peu plus de compréhension du collecteur des ordures de votre système pour optimiser réellement l'utilisation de la mémoire. Mais pour un débutant en GC, il est prudent de supposer que la mémoire appartient à la poubelle une fois que l'objet ne peut plus être atteint.


-1 parce que cet article confond GC et le but de disposer (). Il est vrai que disposer () est là pour nettoyer les ressources non gérées. Mais cela s'appelle de manière déterministe et explicite par votre code. Il ne sera jamais appelé par le collecteur des ordures et le dispositif d'appel () n'entraînera jamais que l'objet étant recueilli.