11
votes

Les faibles sont-ils effacés pendant un gc complet?

J'ai rencontré des problèmes avec une faiblesseHashmap.

Considérez cet exemple de code: p> xxx pré>

Ce code fonctionne. À l'intérieur des boucles, je crée un objet.Lorsque une GC mineure survient, la taille de la carte est égale à 1 à la 1360ème itération. Tout va bien. P>

Maintenant, lorsque je commente cette ligne: P>

//anObject = null; 


2 commentaires

Je pense que votre test n'est pas correct. Si vous changez tandis que (map.size () == 2) { à tandis que (map.size ()> 0) {, les deux tests finiront tous les deux jusqu'à la La carte est vide, peu importe votre commentaire anoObject = null ou non. BTW, j'ai déjà essayé.


Imprimer anObject et autreObject à la fin. Le compilateur voit que vous ne les utilisez plus et que vous pouvez les supprimer plus tôt.


3 Réponses :


10
votes

Le compilateur juste à temps analyse le code, voit que anoObject et autreObject ne sont pas utilisés après la boucle et les supprime de la table de variable locale ou des ensembles les NULL , tandis que la boucle est toujours en marche. Ceci s'appelle la compilation OSR.

Plus tard, le GC recueille les cordes car aucune forte références ne leur reste.

Si vous avez utilisé anObject après la boucle, vous obtiendriez toujours un OutofMemoryError .

Mise à jour: Vous trouverez une discussion plus détaillée sur compilation OSR dans mon blog.


4 commentaires

Je pense que vous avez exactement raison - mais n'est-ce pas une optimisation de JIT potentiellement brisant? Si anoObject a un finaliseur et c'est GC'D avant que la référence ne disparaisse que le finaliseur s'exécutera potentiellement avant que cela soit censé.


Que pouvait-il casser? Lorsque le finaliseur est exécuté, la forte référence n'existe plus.


Il pourrait casser dans le sens où il pourrait exécuter un finisseur plus tôt que ce que vous n'attendez pas; avant que la référence difficile ne soit effectivement sortie de portée.


Bon point. Je suppose que la leçon est que vous ne pouvez pas compter sur quand (ou si ) les finaliseurs sont exécutés. Cela peut être plus tôt que vous n'attendez pas seulement plus tard.



7
votes

Bit de creusement révèle que cela est explicitement couvert dans les JLS, section 12.6.1:

L'optimisation des transformations d'un programme peut être conçu de façon à réduire le nombre d'objets qui sont accessibles à moins de celles qui seraient considérés comme accessibles naïvement être. Par exemple, un générateur de compilateur ou un code peut choisir de définir une variable ou un paramètre qui ne sont plus utilisées null pour que le stockage pour un tel objet potentiellement récupérables plus tôt. Strong> p> Blockquote>

(Bolding est une addition.) P>

http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.6.1 p>

donc, en essence, le JIT est autorisé à supprimer les références fortes à chaque fois qu'il veut si elle peut travailler qu'ils ne seront jamais utilisés à nouveau -. qui est exactement ce qui se passe ici p>

Ceci est une grande question cependant et fait pour un jeu de réflexion qui peut facilement montrer simplement parce qu'un objet semble avoir une référence forte portée, ne signifie pas nécessairement qu'il n'a pas été déchets collectés. ! À la suite de cela, il signifie que vous pouvez explicitement rien de garantie quand un finaliseur fonctionnera, cela peut même être dans le cas où il semble que l'objet est toujours portée p>

Par exemple: p >

List<byte[]> list = new ArrayList<byte[]>();

Object thing = new Object() {
    protected void finalize() {
        System.out.println("here");
    }
};
WeakReference<Object> ref = new WeakReference<Object>(thing);

while(ref.get()!=null) {
    list.add(new byte[10000]);
}
System.out.println("bam");


0 commentaires

7
votes

Juste pour ajouter une petite chose à l'excellente réponse de Joni Salonen et berry120 . Il peut être montré que le JIT est en réalité responsable de la "variable supprimer" la désactivation simplement avec -djava.compiler = Aucun . Une fois que vous l'éteignez, vous obtenez l'Oome.

Si nous voulons savoir ce qui se passe sous les hottes, l'option xx: + impressionnaison montre l'activité JIT. Utilisant avec le code de la question La sortie que nous obtenons est la suivante: xxx

La dernière compilation (avec le drapeau @) est une compilation OSR (sur le remplacement de la pile) ( Vérifiez https://gist.github.com/rednaxelafx/1165804#osr pour plus d'informations des détails). En mots simples, il permet à la machine virtuelle de remplacer une méthode lorsqu'elle est en cours d'exécution et qu'elle est utilisée pour améliorer les performances des méthodes Java bloquées dans des boucles. Je suppose que, après la déclenchement de cette compilation, le JIT supprime les variables qui ne sont plus utilisées.


0 commentaires