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)
(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