12
votes

Lequel de ces objets est éligible pour la collecte des ordures?

C'est une question à laquelle j'ai été posée lors de mon entretien récemment: quel (s) objet "aléatoire" serait collecté lors de l'appel "GC.Collect ()"? strong>

String a = new Random().Next(0, 1) ==1 ? "Whatever 1" : "Whatever 2";

String b = new WeakReference(new Random()).Target.Next(0, 1) == 1 ?
    "Whatever 1" : "Whatever 2";

GC.Collect();


2 commentaires

Tu étais trop poli. Ma réponse serait si importante il y a quelque chose d'horriblement faux ....


serait génial si la balise «Java» est également ajoutée à cette question.


4 Réponses :


13
votes

Les deux aléatoires () instances et le affaiblissement sont éligibles pour la collecte:

  • Le premier aléatoire n'a pas été stocké dans un local, encore moins d'un local qui est lue ultérieurement.
  • Le second aléatoire a été transmis à un affairé , il serait donc correct pour collecter de toute façon , mais le affaiblie elles-mêmes n'est tenu nulle part, de sorte que trop est éligible à la collecte.

    Aucune des chaînes n'est (il n'y a que 2 instances de chaîne ici, pas 4, même si chaque chemin de code possible a été atteint): car ils sont littéraux dans le code C #, ils sont internés une fois qu'ils existent.


6 commentaires

Oui, évidemment, la question concerne les objets «aléatoire», désolé, que j'ai oublié de mentionner cela.


Maintenant, peut-on dire que ma réponse est incorrecte et est la bonne réponse que les deux sont?


Pas vrai si le compilateur les met sur la pile ou les variables locales Il peut toujours voir des références. Le GC.Collect devrait se produire en dehors du site d'appel pour être prévisible.


@Zarat Le compilateur n'inventendra pas les habitants sans bonne raison; toute partie de la pile qu'ils sont encore en est des ordures opaques et est traitée comme telle


@Marcgravell - mais c'est un détail de mise en œuvre. Et le compilateur passe aux locaux lorsque la pile commence à devenir trop profonde. De plus, vous ne pouvez jamais être sûr quelles valeurs de pile sont traitées comme des ordures, rappelez-vous que le GC voit le code de la machine décisté non il.


@Marcgravell "Le compilateur n'inventendra pas les habitants sans bonne raison". En fait, c'est exactement ce qu'un vrai compilateur est susceptible de faire. Par exemple, le modèle d'enregistrement infini de LLVM transforme toutes les valeurs intermédiaires en une nouvelle "variable".



9
votes

Il est vrai que c'est une implémentation (et un compilateur) dépendante. Si tout cela se trouve dans la même méthode que vous ne peut pas savoir quels objets sont toujours sur la pile . Puisque les objets sur la pile sont encore référencés, ils ne seraient pas à collectionner.

Qu'est-ce que l'intervieweur voulait que vous ayez le plus susceptible de faire, c'est vérifier quels objets sont toujours accessibles à l'appel de GC.Collect en supposant une implémentation «parfaite» qui met tout en évidence le plus tôt possible.


2 commentaires

Pourquoi le bowvote? Il est important de savoir que lorsque des tests d'unité de codage impliquant un comportement de GC, je parle d'expérience ici. J'ai explicitement fait une différence entre ce que l'intervieweur a probablement voulu entendre et quelle est la réalité technique.


+1 pour être la première réponse correcte que j'ai lue. "En supposant une implémentation parfaite". Étant donné que la question est absurde, je m'abstiendrais de spéculer sur ce que l'intervieweur pensait avoir demandé.



1
votes

gc.collect est comme dans Java équivalent à system.gc ()

Il "recommande" de vérifier les valeurs null pour les supprimer. Vous ne pouvez pas vraiment dépendre de cette fonctionnalité car il est vraiment automatique contrairement à C ++.

J'espère que cela aide!


0 commentaires

3
votes

Cependant, mon intervieweur voulait entendre autre chose.

Je m'attends à ce qu'ils voulaient entendre une réponse comme celle-ci Marc Gravell a affiché ici, mais qui est basé sur un modèle trop simplifié de la manière dont les ordures ont recueilli des machines virtuelles qui ne ressemblent pas à la réalité.

Par exemple, l'appel à GC.Collect pourrait obtenir l'appel de la queue optimisée auquel cas il n'y a pas de racines globales, de sorte que tous les blocs alloués en tas sont collectés. Ou le compilateur peut créer une nouvelle entrée sur le cadre de pile pour toutes les variables temporaires (pas seulement dans le code source) qui maintient tout accessible et rien ne se recueille. Ou le compilateur peut échanger l'ordre de la création des chaînes A et b et collectez l'objet aléatoire mentionné par le affaiblissement Avant la méthode cible est appelé provoquant une exception de référence null null de sorte que l'autre aléatoire n'est jamais attribué.


3 commentaires

Que voulez-vous dire échanger les cordes et comment est-ce pertinent pour le faibles ?


Je veux dire exécuter nouvelle faiblicielle (nouveau aléatoire ()). Cible.next (0, 1) == 1? "Peu importe 1": "quoi que ce soit 2" avant d'exécuter nouveau aléatoire (). Suivant (0, 1) == 1? "Peu importe 1": "Peu importe 2" .


Oh, j'ai raté la moitié de cela, la collection précoce du affaiblissement cible + exception pourrait se produire dans l'un ou l'autre ordre, c'est juste qu'il n'affecte que l'autre aléatoire si elles sont réorganisées. Et dans ce cas, le compilateur est libre de réorganiser parce que "personne ne saura jamais".