Comment assurer finalize() est toujours appelé (Penser en Java exercice)
Je suis en train, lentement, par Bruce Eckel de Penser en Java 4ème édition, et le problème suivant a moi perplexe:
Créer une classe avec une méthode finalize( ) qui affiche un message. Dans main( ), créez un objet de votre classe. Modifier l'exercice précédent, de sorte que votre finalize( ) sera toujours appelé.
C'est ce que j'ai codé:
public class Horse {
boolean inStable;
Horse(boolean in){
inStable = in;
}
public void finalize(){
if (!inStable) System.out.print("Error: A horse is out of its stable!");
}
}
public class MainWindow {
public static void main(String[] args) {
Horse h = new Horse(false);
h = new Horse(true);
System.gc();
}
}
Il crée un nouveau Horse
objet avec l'opérateur booléen inStable
ensemble de false
. Maintenant, dans le finalize()
méthode, il vérifie pour voir si inStable
est false
. Si elle l'est, il imprime un message.
Malheureusement, aucun message n'est imprimé. Puisque la condition est évaluée à true
, ma conjecture est que finalize()
n'est pas appelée en premier lieu. J'ai exécuter le programme à de nombreuses reprises, et ont vu le message d'erreur d'impression seulement une couple de fois. J'étais sous l'impression que quand System.gc()
est appelé, le garbage collector de recueillir tous les objets qui ne sont pas référencées.
Googler une bonne réponse m'a donné ce lien, ce qui donne beaucoup plus détaillée, code compliqué. Il utilise des méthodes que je n'ai pas vu avant, comme System.runFinalization()
, Runtime.getRuntime()
, et System.runFinalizersOnExit()
.
Est ce que quelqu'un pourrez me donner une meilleure compréhension de la façon dont finalize()
fonctionne et comment le forcer à exécuter, ou de me guider à travers ce qui est fait dans la solution de code?
System.gc()
fait recycle quoi que ce soit.Sur la ligne
h = new Horse(true);
j'ai mis h pour un nouvel objet, ce qui le précédent (qui avait inStable false) non référencées.Ouais, dans ce cas, consulter la deuxième moitié de mon commentaire. Il n'y a pas de garanties. La solution à partir de cette page externe est en fait pas une vraie solution
OriginalL'auteur MattDs17 | 2012-08-19
Vous devez vous connecter pour publier un commentaire.
Lorsque le garbage collector trouve un objet qui est admissible pour la collection, mais a un
finalizer
il ne pas libérer immédiatement. Le garbage collector essaye de compléter aussi rapidement que possible, de sorte qu'il ajoute l'objet à la liste des objets en suspens finaliseurs. Le finaliseur est appelé plus tard sur un thread séparé.Vous pouvez indiquer au système pour essayer de l'exécuter en attendant les finaliseurs immédiatement en appelant la méthode
System.runFinalization
après la collecte des ordures.Mais si vous voulez force le finaliseur à exécuter, vous devez appeler vous-même. Le garbage collector ne pas garantie que tous les objets seront collectées ou que les finaliseurs sera appelée. Il ne fait que du "meilleur effort". Cependant, il est rare que vous n'auriez jamais besoin de forcer un finaliseur à exécuter dans le code réel.
System.gc(); System.runFinalization();
Cela fonctionne quand je l'ai essayer. Je suppose que Système.gc() doit être appelée avant Système.runFinalization(), car il est essentiellement "marques" l'objet "à finaliser", de sorte que quand je lance le Système.runFinalization(), il possède un objet lancé. Est-ce le cas, ou suis-je inexactes dans mes observations?Que pourrait être la façon dont votre machine virtuelle java spécifique est mis en œuvre, mais il n'est pas spécifié pour fonctionner de cette façon.
Lorsque le garbage collector s'exécute, il voit que l'objet n'est pas de vivre et de notes que l'objet a besoin de finalisation. Le finaliseur n'est pas lancé. Il n'y a aucune garantie à propos précisément lorsqu'il s'exécute, mais en l'appelant
System.runFinalization();
rend probablement pour être exécuté.C'est, bien sûr, une partie de la raison pour laquelle vous devriez éviter les finaliseurs, en premier lieu.
Merci, fixe le lien pour pointer vers la nouvelle documentation.
OriginalL'auteur Mark Byers
À l'extérieur de jouet scénarios, il n'est généralement pas possible de garantir qu'un
finalize
sera toujours sur des objets pour lesquels aucun "significative" références existent, parce que le garbage collector n'a aucun moyen de savoir quelles références sont "significatifs". Par exemple, unArrayList
-comme l'objet peut avoir une "claire" méthode qui définit son compte à zéro, et en fait tous les éléments à l'intérieur de la sauvegarde de la matrice de admissibles pour être remplacés par de futursAdd
appels, mais n'a pas clairement les éléments qui la sauvegarde de tableau. Si l'objet a une matrice de taille 50, et sonCount
est de 23, alors il y a peut être pas de chemin d'exécution par le code qui ne pourrait jamais examiner les références stockées dans la dernière 27 fentes de la matrice, mais il n'y aurait aucun moyen pour le garbage collector pour le savoir. Par conséquent, le garbage collector n'aurais jamaisfinalize
sur les objets dans les fentes à moins que, ou jusqu'à ce que le conteneur a remplacé ceux de la matrice de machines à sous, le conteneur abandonné le tableau (peut-être en faveur d'une plus petite), ou toutes enracinées références pour le conteneur lui-même ont été détruits, ou a cessé d'exister.Il existe différents moyens pour encourager le système d'appel
finalize
sur les objets pour lesquels aucun enracinée références arriver à exister (ce qui semble être le point de la question, et que d'autres réponses ont déjà couverts), mais je pense qu'il est important de noter la distinction entre l'ensemble des objets à lequel de fortes ancrées références existent, et l'ensemble des objets que le code peut être intéressé. Les deux ensembles chevauchent largement, mais chaque jeu peut contenir des objets qui ne sont pas dans l'autre. Des objets finaliseurs` exécuter lorsque le GC détermine que les objets n'existent plus, mais pour l'existence des finaliseurs; qui peuvent ou peuvent ne pas coïncider avec le code de temps qu'ils cessent d'être d'intérêt pour personne. Bien qu'il pourrait être utile si l'on pouvait causer des finaliseurs pour s'exécuter sur tous les objets qui ont cessé de l'être, de l'intérêt, qui est en général pas possible.OriginalL'auteur supercat
Un appel à garabage collecter (
System.gc()
) méthode suggère que la Machine Virtuelle Java dépenser l'effort vers le recyclage des objets inutilisés afin de rendre le mémoire qu'ils occupent actuellement disponible pour une réutilisation rapide (j'.e c'est juste une suggestion pour la jvm, et ne se lie pas à l'action, et là, il peut ou ne peut pas faire la même chose). Lorsque le contrôle de retour de l'appel de la méthode, la Machine Virtuelle Java a fait un meilleur effort pour récupérer de l'espace de tous les objets jetés. finalize() est appelée par le garbage collector sur un objet lors de la collecte des ordures détermine qu'il n'y a pas plus de références à l'objetOriginalL'auteur Seeder
l'exécution d'un nouveau constructeur() et du Système.gc() plus de deux fois.
OriginalL'auteur lophyxp
Voici ce qui a fonctionné pour moi (en partie, mais elle illustre l'idée):
La ligne nouveau OLoad(); le truc, car il crée un objet sans la référence joint. Cela permet de Système.gc() exécuter la méthode finalize() qu'il détecte un objet, sans référence aucune. En disant quelque chose comme OLoad o1 = new OLoad(); ne fonctionnera pas, car il va créer une référence qui vit jusqu'à la fin de main(). Malheureusement, cela fonctionne la plupart du temps. Comme d'autres l'ont souligné, il n'y a aucun moyen de s'assurer de finalize() sera toujours appelé, à l'exception de l'appeler vous-même.
OriginalL'auteur dotslash