2010-10-30 12 views
0

1) Est-ce que l'ajout d'une méthode Dispose(), ou finalize, a un impact sur la réalisation d'un objet GC bientôt? Je demande cela car mon manager a écrit du code, en ajoutant une méthode finalize(), dans l'espoir que ce serait GC'd.Quelques questions sur la façon dont le code peut influencer le processus du GC

Mais j'ai soutenu que l'objet doit d'abord être "marqué" pour la collection, s'il répond à certains critères. 2) L'écriture "o = null" (où o est un type ref) a-t-elle un impact sur la réalisation d'un objet GC plus tôt? Soit en C++ ou Java/C#.

Merci

+0

(1) Quelle langue /Éboueur? (2) # 2 est le gazillionth dupe. Pour le numéro 1, de nombreuses questions sur .NET GC ont également abordé cette question. – delnan

Répondre

2

Notez que cette réponse concerne .NET. Je ne sais pas comment Java fait ça, du tout.

Commençons par l'ajout d'un finaliseur, ou plutôt, que se passe-t-il lorsqu'un objet sans un est collecté.

Lorsque GC s'exécute et découvre des objets pour lesquels il n'existe aucune référence racine, ils sont collectés.

Cependant, si vous ajoutez un finaliseur à la classe, lorsque GC découvre que l'objet est admissible à la collecte, il est placé dans une liste, car il a un finaliseur.

Cette liste est traitée en plus du GC normal, et puisque l'objet a maintenant une référence enracinée (cette liste), il n'est temporairement pas éligible pour la collecte. La liste est traitée en itérant sur elle et en appelant tous les finaliseurs. Il y a beaucoup de détails ici que je passe sous silence. Une fois le finaliseur d'un objet appelé, l'objet est supprimé de la liste.

Parfois, plus tard, lorsque GC découvre à nouveau cet objet, bien qu'il ait toujours la méthode finalizer dans son type, l'objet a été marqué de sorte que le finalizer n'a plus besoin de fonctionner, et l'objet est maintenant collecté comme s'il n'avait pas de Finalizer pour commencer. Donc, en fait, l'ajout d'un finaliseur ne fera pas que l'objet sera collecté plus tôt, mais plutôt que l'objet sera collecté plus tard. La seule façon de rendre un objet éligible à la collecte est de supprimer toutes les références rootées. L'appel de Dispose n'a également aucune signification à cet égard. Dispose est juste un appel de méthode, et l'appeler ne marque en aucun cas l'objet comme éligible pour la collecte. Si, après avoir appelé Dispose, vous avez toujours des références enracinées à l'objet, il restera en mémoire et ne sera pas collecté.Cependant, si votre classe a une méthode Dispose et un finaliseur, la méthode Dispose désinscrit généralement l'objet de la finalisation. Fondamentalement, vous dites "Dispose a maintenant pris soin de tout ce que le finaliseur ferait, donc il n'y a plus aucun intérêt à appeler le finaliseur". Dans ce cas, l'appel de la méthode Dispose, puis la suppression de toutes les références en direct à l'objet le rendra éligible à la collecte et ignorera l'étape de finalisation.

À votre deuxième question.

Comme je l'ai dit ci-dessus, vous devez supprimer toutes les références enracinées à l'objet. Une référence enracinée est une référence qui peut être retracée à quelque chose qui vit pendant la durée du programme, qu'il s'agisse de champs statiques, de variables locales sur des piles d'appels en direct, etc. Une fois tous ces éléments disparus, l'objet peut être collecté.

Mais le GC dans .NET est vraiment agressif. JITter stocke des informations à côté du code indiquant à GC quelles parties d'une méthode utilisant les variables locales, et si une variable n'est plus utilisée, par exemple pour la dernière partie d'une méthode, même si la variable fait encore référence à un objet, variable est considérée comme inutile, et donc l'objet peut être collecté.

Par exemple, ici:

public void Test() 
{ 
    object o = new object(); 
    // do something else 
} 

Dans ce cas, tant que la variable o n'est plus utilisée dans la méthode, au cours de ce code « faire quelque chose d'autre », l'objet, il peut être collecté . Le JITter détectera quand le programme est en cours d'exécution dans le débogueur, puis prolongera artificiellement la durée de vie de toutes les variables jusqu'à la fin de leurs portées, afin que vous puissiez inspecter les variables même si techniquement elles ne sont pas considérées comme "actives" plus Mais lorsqu'il n'est pas exécuté dans le débogueur, que o ci-dessus n'est pas explicitement annulé ne signifie rien, l'objet peut encore être collecté. Maintenant, si o était un champ statique, qui dure beaucoup plus longtemps qu'un appel de méthode, alors oui, le paramétrer explicitement sur null vous aidera bien sûr, car maintenant vous supprimez des références enracinées à l'objet.

De même, si la variable est réutilisée ultérieurement dans la méthode, vous pouvez rendre l'objet actuel éligible à la collecte en le définissant sur null. (note Je ne suis pas tout à fait sûr de cela, peut-être le JITter peut voir que la valeur actuelle n'est pas nécessaire, il peut donc être recueillie parce que plus tard vous écraser le contenu de toute façon)

Donc, pour résumer:

  • ne pas ajouter un finaliseur à moins que vous en avez besoin
  • Jeter appel n'a aucune incidence sur la façon dont bientôt l'objet devient éligible pour
  • « marquer » un objet éligible pour la collecte, se débarrasser de tous enracinés références
  • Vous pouvez aider à la collecte en définissant explicitement les variables et les champs à null, mais pour les variables locales qui ne sont plus utilisées par une méthode, cela peut ne pas être nécessaire (mais pas blesser)
+0

Re. 1, Java est similaire - les objets avec les méthodes finaliser ne sont pas GCed jusqu'à la prochaine passe du collecteur. – SimonJ

0

Java:

1) non, finalize() est appelée lorsque le garbage collector détermine que l'objet est GC-mesure - elle n'a aucune incidence sur le moment où GC se produit, ou si l'objet sera GC-ed sur une course donnée. En fait, la mise en œuvre finalize()retarde un objet d'être GCed - la première passe GC détermine que l'objet est GC-able (c'est-à-dire finalize() devrait être appelé) et ce n'est qu'au second passage que l'objet est libéré - en supposant que le finaliseur n'a pas créé de nouvelle référence à l'objet! 2) le maintien sur les références retardera le GC, donc la rupture d'une référence peut permettre à un objet d'être GCed plus tôt si l'objet contenant la référence est toujours joignable. Cependant, il n'est pas garanti que l'objet soit.