J'ai besoin de savoir quand la méthode finalize()
est appelée dans la JVM
. J'ai créé une classe de test qui écrit dans un fichier lorsque la méthode finalize()
est appelée en la remplaçant. Ce n'est pas exécuté. Quelqu'un peut-il me dire la raison pour laquelle il ne s'exécute pas?
En général, il est préférable de ne pas compter sur finalize()
pour effectuer le nettoyage, etc.
Selon le Javadoc (qu’il serait intéressant de lire), c’est:
Appelé par le ramasse-miettes sur un objet lorsque ce dernier détermine qu'il n'y a plus de référence à l'objet.
Comme Joachim l'a souligné, cela peut ne jamais arriver dans la vie d'un programme si l'objet est toujours accessible.
En outre, il n'est pas garanti que le ramasse-miettes s'exécute à un moment donné. En général, ce que j'essaie de dire, c'est que finalize()
n'est probablement pas la meilleure méthode à utiliser en général, sauf si vous avez besoin de quelque chose de spécifique.
La méthode finalize
est appelée lorsqu'un objet est sur le point d'être récupéré. Cela peut être à tout moment une fois qu'il est devenu éligible pour la collecte des ordures.
Notez qu'il est tout à fait possible qu'un objet ne soit jamais récupéré (et donc finalize
n'est jamais appelé). Cela peut se produire lorsque l’objet ne devient jamais éligible pour gc (car il est accessible pendant toute la durée de vie de la machine virtuelle) ou quand aucun garbage collection ne s’exécute réellement entre le moment où l’objet devient éligible et le moment où la JVM s’arrête d’exécuter programmes de test).
Il existe des moyens de dire à la machine virtuelle Java d'exécuter finalize
sur des objets pour lesquels elle n'a pas encore été appelée, mais leur utilisation n'est pas non plus une bonne idée (les garanties de cette méthode ne sont pas non plus très solides).
Si vous comptez sur finalize
pour le bon fonctionnement de votre application, vous faites quelque chose de mal. finalize
devrait only être utilisé pour le nettoyage des ressources (généralement non Java). Et c’est exactement, car la machine virtuelle Java ne garantit pas que finalize
sera jamais appelé sur un objet.
protected void finalize() throws Throwable {}
- chaque classe hérite de la méthode
finalize()
de Java.lang.Object- la méthode est appelée par le ramasse-miettes lorsqu'il détermine plus de références à l'objet existe
- la méthode Object finalize n'effectue aucune action mais peut être remplacée par n'importe quelle classe
- normalement, il devrait être remplacé par le nettoyage des ressources non-Java, c'est-à-dire la fermeture de un fichier
en cas de substitution de
finalize()
, il est recommandé d'utiliser un déclaration try-catch-finally et à appelez toujourssuper.finalize()
. Ce est une mesure de sécurité à prendre pour que vous le fassiez ne manquez pas par inadvertance la fermeture d'un ressource utilisée par les objets appelant classeprotected void finalize() throws Throwable { try { close(); // close open files } finally { super.finalize(); } }
toute exception levée par
finalize()
lors du ramassage des ordures interrompt le la finalisation mais est par ailleurs ignoréefinalize()
n'est jamais exécuté plus d'une fois sur un objet
cité de: http://www.janeg.ca/scjp/gc/finalize.html
Vous pouvez également consulter cet article:
La méthode Java finalize()
n'est pas un destructeur et ne doit pas être utilisée pour gérer la logique dont dépend votre application. La spécification Java indique qu'il n'y a aucune garantie que la méthode finalize
soit appelée pendant la durée de vie de l'application.
Ce que vous voulez probablement est une combinaison de finally
et d'une méthode de nettoyage, comme dans:
MyClass myObj;
try {
myObj = new MyClass();
// ...
} finally {
if (null != myObj) {
myObj.cleanup();
}
}
Consultez Effective Java, 2e édition, page 27 . Point 7: Évitez les finaliseurs
Les finaliseurs sont imprévisibles, souvent dangereux et généralement inutiles. ne faites jamais quelque chose de très important dans un finaliseur. jamais dépend d'un finaliseur pour mettre à jour l'état persistant critique.
Pour mettre fin à une ressource, utilisez try-finally à la place:
// try-finally block guarantees execution of termination method Foo foo = new Foo(...); try { // Do what must be done with foo ... } finally { foo.terminate(); // Explicit termination method }
Quand la méthode
finalize()
est-elle appelée en Java?
La méthode finalize sera appelée une fois que le CPG aura détecté que l’objet n’est plus accessible et avant qu’il ne récupère réellement la mémoire utilisée par l’objet.
Si un objet ne devient jamais inaccessible, finalize()
ne sera jamais appelé.
Si le CPG ne fonctionne pas, alors finalize()
ne pourra jamais être appelé. (Normalement, le CPG ne s'exécute que lorsque la JVM a décidé qu'il y avait probablement assez de déchets pour que cela en vaille la peine.)
Plusieurs cycles peuvent être nécessaires avant que le CPG détermine qu'un objet spécifique est inaccessible. (Les GC Java sont généralement des collecteurs "générationnels" ...)
Une fois que le GC détecte qu'un objet est inaccessible et finalisable, il est placé dans une file d'attente de finalisation. La finalisation se produit généralement de manière asynchrone avec le CPG normal.
(La spécification de la machine virtuelle Java réellement autorise une machine virtuelle Java à jamais exécute les finaliseurs ... à condition qu'elle ne récupère pas l'espace utilisé par les objets. Une machine virtuelle Java implémentée de cette façon serait paralysé/inutile, mais si ce comportement est "autorisé".)
Le résultat est qu’il n’est pas sage de s’appuyer sur la finalisation pour faire des choses qui doivent être faites dans un laps de temps défini. La "meilleure pratique" consiste à ne pas les utiliser du tout. Il devrait exister un meilleur moyen (c'est-à-dire plus fiable) de faire ce que vous essayez de faire avec la méthode finalize()
.
La seule utilisation légitime de la finalisation consiste à nettoyer les ressources associées aux objets perdus par le code de l'application. Même alors, vous devriez essayer d'écrire le code de l'application pour qu'il ne perde pas les objets en premier lieu. (Par exemple, utilisez Java 7+ try-with-resources pour vous assurer que close()
est toujours appelé ...)
J'ai créé une classe de test qui écrit dans un fichier lorsque la méthode finalize () est appelée en la remplaçant. Ce n'est pas exécuté. Quelqu'un peut-il me dire la raison pour laquelle il ne s'exécute pas?
C'est difficile à dire, mais il y a quelques possibilités:
Comme il existe une incertitude dans l’appel de la méthode finalize () par la machine virtuelle Java (il n’est pas certain que finalize () qui est surchargé sera exécuté ou non), le meilleur moyen d’observer ce qui se passe lors de l’appel de finalize () est de: forcer la JVM à appeler le garbage collection à l'aide de la commande System.gc()
.
Plus précisément, finalize () est appelée lorsqu'un objet n'est plus utilisé. Mais lorsque nous essayons de l'appeler en créant de nouveaux objets, il n'y a aucune certitude quant à son appel. Donc, pour plus de certitude, nous créons un objet null
c
qui n'a évidemment aucune utilisation future. Nous voyons donc l'appel de finalisation de l'objet c
.
Exemple
class Car {
int maxspeed;
Car() {
maxspeed = 70;
}
protected void finalize() {
// Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
// Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection
System.out.println("Called finalize method in class Car...");
}
}
class Bike {
int maxspeed;
Bike() {
maxspeed = 50;
}
protected void finalize() {
System.out.println("Called finalize method in class Bike...");
}
}
class Example {
public static void main(String args[]) {
Car c = new Car();
c = null; // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
Bike b = new Bike();
System.gc(); // should clear c, but not b
for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
System.out.print("\t" + b.maxspeed);
if (b.maxspeed > 50) {
System.out.println("Over Speed. Pls slow down.");
}
}
}
}
Sortie
Called finalize method in class Car...
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51Over Speed. Pls slow down.
52Over Speed. Pls slow down.
53Over Speed. Pls slow down.
54Over Speed. Pls slow down.
55Over Speed. Pls slow down.
56Over Speed. Pls slow down.
57Over Speed. Pls slow down.
58Over Speed. Pls slow down.
59Over Speed. Pls slow down.
60Over Speed. Pls slow down.
61Over Speed. Pls slow down.
62Over Speed. Pls slow down.
63Over Speed. Pls slow down.
64Over Speed. Pls slow down.
65Over Speed. Pls slow down.
66Over Speed. Pls slow down.
67Over Speed. Pls slow down.
68Over Speed. Pls slow down.
69Over Speed. Pls slow down.
70Over Speed. Pls slow down.
Remarque - Même après l'impression jusqu'à 70 et après quoi l'objet b n'est pas utilisé dans le programme, il est incertain que b soit effacé ou non par la JVM puisque "la méthode de finalisation appelée dans la classe Bike ..." n'est pas imprimée. .
finaliser imprimera le compte pour la création de classe.
protected void finalize() throws Throwable {
System.out.println("Run F" );
if ( checkedOut)
System.out.println("Error: Checked out");
System.out.println("Class Create Count: " + classCreate);
}
principale
while ( true) {
Book novel=new Book(true);
//System.out.println(novel.checkedOut);
//Runtime.getRuntime().runFinalization();
novel.checkIn();
new Book(true);
//System.runFinalization();
System.gc();
Comme vous pouvez le voir. Les sorties suivantes montrent que le gc a été exécuté pour la première fois lorsque le nombre de classes est de 36.
C:\javaCode\firstClass>Java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F
Après avoir lutté avec les méthodes de finalisation dernièrement (afin de disposer des pools de connexions lors des tests), je dois dire que la finalisation manque beaucoup de choses. En utilisant VisualVM pour observer et en utilisant des références faibles pour suivre l'interaction réelle, j'ai constaté que les choses suivantes sont vraies dans un environnement Java 8 (JDK Oracle, Ubuntu 15):
Pensée finale
La méthode de finalisation n'est pas fiable mais ne peut être utilisée que pour une seule chose. Vous pouvez vous assurer qu'un objet a été fermé ou éliminé avant la collecte des ordures, ce qui permet de mettre en œuvre un système de sécurité intégrée si les objets ayant une durée de vie plus complexe impliquant une action de fin de vie sont correctement gérés. C’est la seule raison pour laquelle je pense que cela en vaut la peine de l’annuler.
Parfois, lorsqu'il est détruit, un objet doit effectuer une action. Par exemple, si un objet possède une ressource non Java telle qu'un descripteur de fichier ou une police, vous pouvez vérifier que ces ressources sont libérées avant la destruction d'un objet. Pour gérer de telles situations, Java propose un mécanisme appelé "finalisation". En le finalisant, vous pouvez définir des actions spécifiques qui se produisent lorsqu'un objet est sur le point d'être supprimé du garbage collector . Pour ajouter un finaliseur à une classe, définissez simplement la méthode finalize () . Java run time appelle cette méthode chaque fois qu'il est sur le point de supprimer un objet de cette classe. Dans finalize method (), vous indiquez les actions à effectuer avant de détruire un objet . Le garbage collector recherche périodiquement des objets qui ne font plus référence à un état en cours ou indirectement à un autre objet référencé. Avant la publication d'un actif, le moteur d'exécution Java appelle la méthode finalize () sur l'objet. La méthode finalize () a la forme générale suivante:
protected void finalize(){
// This is where the finalization code is entered
}
Avec le mot clé protected, l'accès à finalize () par un code en dehors de sa classe est empêché . Il est important de comprendre que finalize () est appelé juste avant la récupération de place . Il n'est pas appelé lorsqu'un objet quitte la portée, par exemple. Cela signifie que vous ne pouvez pas savoir quand ni si finalize () sera exécuté. Par conséquent, le programme doit fournir d'autres moyens pour libérer des ressources système ou d'autres ressources utilisées par l'objet. Vous ne devriez pas vous fier à finalize () pour un fonctionnement normal du programme.
Un objet devient éligible pour le garbage collection ou le GC s'il n'est pas accessible à partir de threads en direct ou de références statiques, autrement dit, vous pouvez dire qu'un objet devient éligible pour le garbage collection si toutes ses références sont nulles. Les dépendances cycliques ne sont pas comptées comme référence. Par conséquent, si l'objet A a la référence de l'objet B et que l'objet B a la référence de l'objet A et qu'ils n'ont pas d'autre référence active, les objets A et B seront éligibles pour la récupération de place. Généralement, un objet devient éligible pour la récupération de place en Java dans les cas suivants:
finalize La méthode n'est pas garantie. Cette méthode est appelée lorsque l'objet devient éligible pour GC. Il existe de nombreuses situations dans lesquelles les objets ne peuvent pas être ramassés.
Classe où nous substituons la méthode finalize
public class TestClass {
public TestClass() {
System.out.println("constructor");
}
public void display() {
System.out.println("display");
}
@Override
public void finalize() {
System.out.println("destructor");
}
}
Les chances de finaliser la méthode étant appelée
public class TestGarbageCollection {
public static void main(String[] args) {
while (true) {
TestClass s = new TestClass();
s.display();
System.gc();
}
}
}
lorsque la mémoire est surchargée d'objets de dump, le gc appellera la méthode finalize
lancez et voyez la console, où vous ne trouvez pas la méthode finalize appelée fréquemment, lorsque la mémoire est surchargée, la méthode finalize sera appelée
finalize()
est appelé juste avant la récupération de place. Il n'est pas appelé lorsqu'un objet sort de la portée. Cela signifie que vous ne pouvez pas savoir quand ni même si finalize()
sera exécuté.
Exemple:
Si votre programme se termine avant que le ramasse-miettes ne se produise, alors finalize()
ne sera pas exécuté. Par conséquent, il doit être utilisé comme procédure de sauvegarde pour garantir le traitement correct des autres ressources, ou pour des applications à usage spécial, et non comme le moyen utilisé par votre programme dans son fonctionnement normal.
Java permet aux objets d'implémenter une méthode appelée finalize () cela pourrait être appelé.
la méthode finalize () est appelée si le ramasse-miettes tente d'exécuter collecter l'objet.
Si le ramasse-miettes ne s'exécute pas, la méthode n'est pas appelée.
Si le garbage collector ne parvient pas à collecter l'objet et tente d'exécuterencore, la méthode n'est pas appelée dans un deuxième temps.
En pratique, il est très peu probable que vous l'utilisiez dans des projets réels.
Gardez juste à l’esprit qu’il pourrait ne pas être appelé et que c’est définitivement ne sera pas appelé deux fois. La méthode finalize () peut exécuter zéro ou un temps.
Dans le code suivant, la méthode finalize () ne produit aucun résultat lorsque nous lancez-le puisque le programme se ferme avant qu’il soit nécessaire d’exécuter le Éboueur.