8
votes

Quand les faibles références faibles sont-elles nulles?

Je suivez un objet en utilisant affaiblie ( Référence faible faible ) dans ma classe foo . Cette classe a un destructeur dans lequel j'ai besoin d'accéder à cet objet suivi. L'objet i Track suive également FOO à l'aide de faiblicielle .

Alors maintenant, je me demande, quand exactement "la mise à zéro" du faiblice se produit? Est-ce que tout affaiblie est annulé avant que tout finisseur ne soit exécuté ou que chacun d'entre eux soit annulé juste avant que le finaliseur de l'objet qu'ils suivent est sur le point de courir?

mise à jour

Maintenant, je me demande aussi si peut-être mono peut éclairer celui-ci ( lien 1 , link 2 ). Mais je suis un peu inquiet que, peut-être que ms gc et mono gc peut aborder ce problème différemment et être incompatible . .


6 commentaires

Wow, c'est une documentation déroutante ... c'est looks comme la petite documentation de référence faibles devait parler de la finalisation, pas de la collecte des ordures - mais ce n'est pas clair.


Je suis allé chercher à travers l'ancien code source SSCLI pour essayer de voir ce que je pouvais trouver. N'a rien trouvé encore, mais a trouvé un commentaire intrigant à l'intérieur de la cible getter : "ne devrait se produire que lorsqu'il est utilisé illégalement, comme utiliser une faiblence d'un finaliseur" - peut-être que ce que vous essayez de faire est condamné quand même.


Pas une réponse, mais il convient de noter que vous devriez généralement éviter les destructeurs et c'est probablement un problème XY.


@HENKHOLTERMAN, je suis en train de mettre en œuvre un dictionnaire faible qui devrait automatiquement nettoyer les références faibles annulées. Je peux difficilement imaginer comment vous pourriez faire cela sans destructeurs.


Les choses qui ont besoin de nettoyer ne doivent pas être placées dans un dictionnaire faible.


J'ai dit des références annulées. Comme dans faim de faim aux éléments réels, mais depuis que ceux-ci ont été collectés, le faibl libérant.target est maintenant null. Cependant, l'objet faim est toujours dans le dictionnaire et gaspille de l'espace.


3 Réponses :


4
votes

Vous pouvez vérifier par vous-même avec un simple programme de test. Mais je trouve la documentation pour le type type soit un peu plus clair que la page que vous regardiez.

En particulier, le drapeau appelé "court" et "long" dans votre page liée est appelé TrackResurrection dans la documentation du constructeur actuel . Et la description du paramètre lit:

Indique quand arrêter de suivre l'objet. Si vrai, l'objet est suivi après la finalisation; Si FAUX, l'objet n'est suivi que jusqu'à la finalisation.

La section "remarques" lit également:

Si la trackResurrection est fausse, une référence faible faible est créée. Si la trackresurrection est vraie, une longue référence faible est créée.

Ceci confirme que lorsque vous utilisez une référence faible «courte», un objet finalisé ne sera plus suivi (c.-à-d. La cible devient null ) par le ) Affectement objet, mais lorsque vous utilisez une "longue" référence faible, ce sera.

Pour les deux types de référence faible, un objet qui a été recueilli à la poubelle ne sera certainement plus suivi (évidemment).

En général, aucun autre thread dans votre programme ne devrait être capable d'observer un objet lorsque le thread de finaliseur fait réellement son travail, de sorte que le moment précis de la référence "courte" faible lorsque la cible propriété est définie sur null semble sans intérêt pour moi. Si un autre thread dans votre programme observe la valeur non nulle, le finaliseur n'a pas encore été exécuté. Si elle l'observe comme nul, le finaliseur a couru. Ce « autre thread » ne doit pas exécuter lui-même alors que le thread finaliseur travaille, donc la finalisation devrait être essentiellement atomique dans la mesure où « l'autre thread » est concerné.


0 commentaires

5
votes

Je pensais écrire un petit programme de démonstration qui démontre la différence. S'est avéré être un peu plus difficile que je comptais. Le premier ingrédient nécessaire consiste à garantir le ralentissement du filetage de finaliseur afin que vous puissiez observer la valeur de faiblesseReReference.Inalive sans risquer d'être affectée par une course avec le fil de finalisation. Donc j'ai utilisé: xxx

puis une petite classe qui sera la cible de la faiblesseFerence: xxx

alors un programme qui démontre la différence entre Référence longue et faible faible: xxx

Vous devez exécuter ce programme afin que le débogueur ne puisse affecter la durée de vie des objets. Sélectionnez la version de déverrouillage et modifiez un paramètre de débogueur: Outils + Options, débogage, Général, décanter l'option «Supprimer Jit Optimization».

a révélé que l'ordre de finalisation des objets n'est vraiment pas déterministe. La commande est différente chaque fois que vous exécutez le programme. Nous voulons que l'objet FinalistierDelayer soit finalisé en premier, mais cela ne se produit pas toujours. Je pense il s'agit d'un effet secondaire sur la fonctionnalité de randomisation de la mise en page d'espace d'adresse intégrée, il rend le code géré très difficile à attaquer. Mais courir assez souvent et vous obtiendrez éventuellement:

Délai de retarder ...
Court alive = faux
Long alive = vrai
Retard fait
Exemple 1 Finalisé
Exemple 2 Finalized
Finalisation effectuée
Longue vivance = faux

longue histoire courte:

  • Un court métrage de référence faibles isalive à false dès que l'objet est collecté et placé sur la file d'attente fragile, prête à être finalisée. L'objet existe toujours physiquement, mais aucune forte références n'existe plus, elle sera bientôt finalisée.
  • Une longue référence faible maintient la trace de l'objet tout au long de sa vraie vie, y compris sa vie sur la file d'attente fragile. Isalive ne sera pas défini sur false jusqu'à ce que son finalizer soit terminé.

    méfiez-vous d'une bizarrerie lorsque l'objet est ressuscité, replacé de la file d'attente à fragilité à l'enceinte normale lorsqu'une référence forte est recréée. Pas quelque chose que j'ai exploré dans ce programme de démonstration, mais une longue référence faible sera nécessaire pour observer cela. La raison de base pour laquelle vous auriez besoin d'une longue référence faible.


0 commentaires

0
votes

Donc après de nombreuses recherches, j'ai pu trouver cet article ancien Collection ordures Partie 2: Gestion automatique de la mémoire dans le cadre Microsoft .NET ( 1 discute de la résurrection et de la file d'attente fragile):

Maintenant, voici ce qui se passe lorsqu'une collection de déchets (GC) fonctionne:

  1. Le collecteur des ordures construit un graphique de tous les objets accessibles. Partie 1 de cet article discuté de la manière dont cela fonctionne.

  2. Le collecteur des ordures scanne la courte table de référence faible. Si un pointeur dans la table fait référence à un objet qui ne fait pas partie du graphique , le pointeur identifie un objet inaccessible et la fente dans la table de référence faibles courte est définie sur NULL .

  3. Le collecteur des ordures scanne la file d'attente de finalisation . Si un pointeur de la file d'attente fait référence à un objet qui ne fait pas partie du graphique, le pointeur identifie un objet inaccessible et le pointeur est déplacé de la file d'attente de finalisation à la file d'attente à fragilité. À ce stade, l'objet est ajouté au graphique car l'objet est maintenant considéré comme accessible.

  4. Le collecteur des ordures scanne la longue table de référence faible. Si un pointeur dans la table fait référence à un objet qui ne fait pas partie du graphique (qui contient maintenant les objets pointés par des entrées dans la file fragile), le pointeur identifie un objet inaccessible et l'emplacement est défini sur NULL.

  5. Le collecteur des ordures compacte la mémoire, pressant les trous laissés par les objets inaccessibles.

    Alors même si ma classe FOO a un finisseur et donc, il sera donc dans une file fragile (qui est considérée comme une racine) - la résolution de faibles références faibles arrive avant que cet objet ne soit enraciné Dans la file fragile, ce qui signifie que la référence faible faible sera NULL:

    Le collecteur de déchets Définit le pointeur sur NULL dans la table de référence faibles courte dès qu'il a déterminé que l'objet est inaccessible. Si l'objet a une méthode de finalisation, la méthode n'a pas encore été appelée afin que l'objet existe toujours. Si l'application accède à la propriété cible de l'objet affairé, alors NULL sera renvoyé même si l'objet existe toujours.


    En outre, comme mentionné sur Weblog Yun Jin's's Weblog < / a>, il n'est généralement pas bon de faire référence à des objets finalisables dans les finaliseurs, mais faim librable est un peu une exception (bien que Ce n'était pas toujours le cas ). Etant donné que affaibleur est un objet avec le finaliseur, s'il est accédé à la finaliseur de FOO , il aurait peut-être été déjà finalisé (auquel cas la propriété cible retournera toujours NULL, malgré le fait que l'objet suivi pourrait toujours être alive et bien ( Plus d'infos ).


    Je viens de confirmer que ordures mono Collector est cohérent avec ce comportement.


    Référence utile:

    - faim de la source code source
    - afférence code source


2 commentaires

"Depuis que l'affaiblissement est un objet avec le finaliseur" - es-tu toujours sûr que vous êtes sur la bonne voie ici?


@Henkoleshterman, il complique beaucoup les choses par beaucoup, mais j'espère que je peux travailler autour de cela en quelque sorte. Par exemple, en héritant d'une faiblesse de la logique fantaisie, j'ai besoin de là. :-) L'ordre de ce que GC fait est absolument crucial de bien réussir.