Quand la méthode finalize () est-elle appelée en Java?


330

J'ai besoin de savoir quand la finalize()méthode est appelée dans le JVM. J'ai créé une classe de test qui écrit dans un fichier lorsque la finalize()méthode est appelée en la remplaçant. Il n'est pas exécuté. Quelqu'un peut-il me dire pourquoi il ne s'exécute pas?


34
Juste comme une note latérale: finaliser est marqué comme obsolète dans Java 9
Reg


si quelque chose a une référence à votre objet ou même à la classe. finalize()et la collecte des ordures n'a aucun impact.
ha9u63ar

Réponses:


273

En général, il est préférable de ne pas compter sur finalize()le nettoyage, etc.

Selon le Javadoc (qu'il vaut la peine de lire), c'est:

Appelé par le garbage collector sur un objet lorsque le garbage collection détermine qu'il n'y a plus de références à l'objet.

Comme l'a souligné Joachim, cela peut ne jamais se produire dans la vie d'un programme si l'objet est toujours accessible.

En outre, le garbage collector n'est pas garanti pour fonctionner à un moment spécifique. En général, ce que j'essaie de dire, ce n'est finalize()probablement pas la meilleure méthode à utiliser en général, sauf si vous avez besoin de quelque chose de spécifique.


19
En d'autres termes (juste pour clarifier pour les futurs lecteurs), il n'est jamais appelé sur la classe principale, car, lorsque la classe principale se ferme, aucune ordure n'a besoin d'être collectée. Le système d'exploitation nettoie tout ce que l'application a utilisé de toute façon.
Mark Jeronimus

113
"ce n'est pas la meilleure méthode à utiliser ... à moins qu'il y ait quelque chose de spécifique pour lequel vous en avez besoin" - euh, cette phrase s'applique à 100% de tout, donc n'est pas utile. La réponse de Joachim Sauer est bien meilleure
BT

1
@ Zom-B, votre exemple est utile pour la clarification, mais juste pour être pédant, il pourrait probablement être appelé sur la classe principale si la classe principale crée un thread non démon et retourne ensuite?
Tom G

3
Quelles sont donc les situations où finalizecela serait utile?
nbro

3
@MarkJeronimus - En fait, ce n'est pas pertinent. La finalize()méthode on pour la classe principale est invoquée lorsqu'une >> instance << de la classe est récupérée, et non lorsque la méthode principale se termine. De plus, la classe principale peut être récupérée avant la fin de l'application; par exemple, dans une application multithread où le thread "principal" crée d'autres threads puis revient. (En pratique, un chargeur de classe non standard serait requis ....)
Stephen C

379

La finalizeméthode est appelée lorsqu'un objet est sur le point de récupérer les ordures. Cela peut être à tout moment après qu'il soit 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 JVM) ou lorsqu'aucune récupération de place ne s'exécute réellement entre le moment où l'objet devient éligible et le moment où la JVM cesse de s'exécuter (cela se produit souvent avec simple programmes de test).

Il existe des moyens de dire à la JVM de s'exécuter finalizesur des objets auxquels 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 très fortes non plus).

Si vous comptez sur finalizele bon fonctionnement de votre application, vous faites quelque chose de mal. finalizedevrait uniquement être utilisé pour le nettoyage des ressources (généralement non Java). Et c'est exactement parce que la JVM ne garantit pas que l' finalizeon appelle jamais un objet.


2
@Rajesh. Ce n'est pas un problème de "durée de vie". Vous pouvez mettre votre programme dans une boucle infinie (pendant des années), et si le ramasse-miettes n'est pas nécessaire, il ne s'exécutera jamais.
ChrisCantrell

5
@VikasVerma: le remplacement parfait n'est rien: vous ne devriez pas en avoir besoin. Le seul cas où cela aurait du sens est que votre classe gère une ressource externe (comme une connexion TCP / IP, un fichier ... tout ce que le GC Java ne peut pas gérer). Dans ces cas, l' Closableinterface (et l'idée derrière elle) est probablement ce que vous voulez: faire .close()fermer / supprimer la ressource et demander à l'utilisateur de votre classe de l'appeler au bon moment. Vous voudrez peut -être ajouter une finalizeméthode "juste pour être enregistré", mais ce serait plus un outil de débogage qu'un correctif réel (car il n'est pas assez fiable).
Joachim Sauer

4
@Dragonborn: c'est en fait une question très différente et doit être posée séparément. Il existe des hooks d'arrêt, mais ils ne sont pas garantis si la JVM s'arrête de manière inattendue (aka se bloque). Mais leurs garanties sont nettement plus fortes que celles des finaliseurs (et elles sont également plus sûres).
Joachim Sauer

4
Votre dernier paragraphe dit de l'utiliser uniquement pour nettoyer les ressources, même s'il n'y a aucune garantie qu'il sera appelé. Cet optimisme parle-t-il? Je suppose que quelque chose de peu fiable, car cela ne conviendrait pas non plus pour nettoyer les ressources.
Jeroen Vannevel

2
Les finaliseurs peuvent parfois sauver la mise ... J'ai eu un cas où une bibliothèque tierce utilisait un FileInputStream, sans jamais le fermer. Mon code appelait le code de la bibliothèque, puis a essayé de déplacer le fichier, échouant car il était toujours ouvert. J'ai dû forcer l'appel System.gc()pour appeler FileInputStream :: finalize (), puis j'ai pu déplacer le fichier.
Elist

73
protected void finalize() throws Throwable {}
  • chaque classe hérite de la finalize()méthode de java.lang.Object
  • la méthode est appelée par le garbage collector lorsqu'il détermine qu'il n'existe plus de références à l'objet
  • la méthode Object finalize n'effectue aucune action mais elle peut être remplacée par n'importe quelle classe
  • normalement, il doit être remplacé pour nettoyer les ressources non Java, c'est-à-dire fermer un fichier
  • en cas de surcharge, finalize()il est recommandé d'utiliser une instruction try-catch-finally et de toujours appeler super.finalize(). Il s'agit d'une mesure de sécurité pour vous assurer que vous ne manquez pas par inadvertance de fermer une ressource utilisée par les objets appelant la classe

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • toute exception levée finalize()lors de la récupération de place interrompt la finalisation mais est sinon ignorée

  • finalize() n'est jamais exécuté plus d'une fois sur un objet

extrait de: http://www.janeg.ca/scjp/gc/finalize.html

Vous pouvez également consulter cet article:


25
L'article JavaWorld auquel vous vous connectez date de 1998 et contient des conseils intéressants, en particulier la suggestion d'appeler System.runFinalizersOnExit () pour garantir l'exécution des finaliseurs avant la fermeture de la JVM. Cette méthode est actuellement déconseillée, avec le commentaire «Cette méthode est intrinsèquement dangereuse. Il peut en résulter que les finaliseurs soient appelés sur des objets actifs tandis que d'autres threads manipulent simultanément ces objets, entraînant un comportement erratique ou un blocage. Je ne ferai donc pas cela.
Greg Chabala

3
Puisque runFinalizerOnExit () n'est PAS thread-safe, ce que l'on pourrait faire est Runtime.getRuntime (). AddShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); dans le constructeur de la classe.
Ustaman Sangat

2
@Ustaman Sangat C'est une façon de le faire, mais rappelez-vous que cela définit une référence à votre instance à partir du shutdownHook, ce qui garantit à peu près que votre classe n'est jamais garbage collection. En d'autres termes, c'est une fuite de mémoire.
pieroxy

1
@pieroxy, alors que je suis d'accord avec tout le monde ici pour ne pas utiliser finalize () pour quoi que ce soit, je ne vois pas pourquoi il devrait y avoir une référence à partir du crochet d'arrêt. On pourrait avoir une référence douce.
Ustaman Sangat

25

La finalize()méthode Java 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 lefinalize méthode est appelée du tout pendant la durée de vie de l'application.

Ce que vous voulez probablement, c'est une combinaison de finallyet une méthode de nettoyage, comme dans:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

    if (null != myObj) {
        myObj.cleanup();
    }
}

20

Consultez Efficace 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 rien de critique dans le temps dans un finaliseur. ne dépendez jamais d'un finaliseur pour mettre à jour l'état persistant critique.

Pour mettre fin à une ressource, utilisez plutôt try-finally:

// 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
}

3
ou utilisez try-with-resources
Gabriel Garcia

3
Cela suppose que la durée de vie d'un objet est dans le cadre d'une fonction. Ce qui, bien sûr, n'est pas le cas auquel le PO fait référence, ni le cas fondamentalement dont tout le monde a besoin. Pensez «compte de référence de la valeur de retour du moteur de cache». Vous souhaitez libérer l'entrée de cache lorsque la dernière référence est libérée, mais vous ne savez pas quand la dernière référence est libérée. finalize () peut décrémenter un compteur de références, par exemple ... mais si vous demandez à vos utilisateurs d'appeler explicitement une fonction gratuite, vous demandez des fuites de mémoire. Habituellement, je fais juste les deux (fonction de libération + double vérification dans la finalisation ...) ...
Erik Aronesty

16

Quand la finalize()méthode est-elle appelée en Java?

La méthode de finalisation sera appelée après que le GC détecte 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()il ne sera jamais appelé dessus.

  • Si le GC ne fonctionne pas, il se finalize()peut qu'il ne soit jamais appelé. (Normalement, le GC ne s'exécute que lorsque la JVM décide qu'il y a probablement suffisamment de déchets pour que cela en vaille la peine.)

  • Il peut s'écouler plus d'un cycle GC avant que le GC 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 GC normal.

(La spécification JVM permet en fait à une JVM de ne jamais exécuter les finaliseurs ... à condition qu'elle ne récupère pas l'espace utilisé par les objets. Une JVM qui a été implémentée de cette façon serait paralysée / inutile, mais si ce comportement est "autorisé" .)

Le résultat est qu'il n'est pas judicieux de s'appuyer sur la finalisation pour faire les choses qui doivent être faites dans un délai défini. Il est préférable de ne pas les utiliser du tout. Il devrait y avoir une meilleure façon (c'est-à-dire plus fiable) de faire tout ce que vous essayez de faire dans la finalize()méthode.

La seule utilisation légitime pour la finalisation est de nettoyer les ressources associées aux objets qui ont été perdus par le code d'application. Même alors, vous devriez essayer d'écrire le code d'application afin qu'il ne perde pas les objets en premier lieu. (Par exemple, utilisez Java 7+ try-with-resources pour vous assurer qu'il 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. Il n'est pas exécuté. Quelqu'un peut-il me dire pourquoi il ne s'exécute pas?

C'est difficile à dire, mais il y a quelques possibilités:

  • L'objet n'est pas récupéré car il est toujours accessible.
  • L'objet n'est pas récupéré car le GC ne s'exécute pas avant la fin de votre test.
  • L'objet est trouvé par le GC et placé dans la file d'attente de finalisation par le GC, mais la finalisation n'est pas terminée avant la fin de votre test.

10

Comme il y a une incertitude dans l'appel de la méthode finalize () par JVM (je ne sais pas si finalize () qui est surchargé sera exécuté ou non), à des fins d'étude, la meilleure façon d'observer ce qui se passe lorsque finalize () est appelé, est de forcer la JVM à appeler le garbage collection par 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 de son appel. Donc, pour plus de certitude, nous créons un nullobjet cqui n'a évidemment aucune utilité future, d'où nous voyons l' cappel de finalisation de l'objet .

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.");
            }
        }
    }
}

Production

    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 laquelle l'objet b n'est pas utilisé dans le programme, il y a une incertitude que b est effacé ou non par la JVM puisque "la méthode de finalisation appelée dans la classe Bike ..." n'est pas imprimée.


10
L'appel System.gc();n'est pas une garantie que la récupération de place sera réellement exécutée.
Simon Forsberg

3
Il n'est pas non plus garanti quel type de collecte sera exécuté. Pertinent puisque la plupart des GC Java sont des collecteurs "générationnels".
Stephen C

5

finalize imprimera le décompte pour la création de la 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 résultats suivants montrent que le GC a été exécuté 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

4

Ayant récemment lutté avec les méthodes du finaliseur (afin de disposer des pools de connexions pendant les tests), je dois dire que le finaliseur manque de beaucoup de choses. En utilisant VisualVM pour observer ainsi qu'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 (Oracle JDK, Ubuntu 15):

  • Finalize n'est pas appelé immédiatement, le Finalizer (partie GC) possède individuellement la référence de manière insaisissable
  • Le garbage collector par défaut regroupe les objets inaccessibles
  • Finalize est appelé en bloc, pointant vers un détail d'implémentation selon lequel le garbage collector libère les ressources.
  • L'appel à System.gc () n'entraîne souvent pas la finalisation plus fréquente des objets, mais simplement la finalisation par le Finalizer d'un objet inaccessible.
  • La création d'un vidage de thread entraîne presque toujours le déclenchement du finaliseur en raison d'un surdébit de tas élevé lors de l'exécution du vidage de tas ou d'un autre mécanisme interne
  • Les coutures de finalisation doivent être liées soit par les besoins en mémoire (libérer plus de mémoire), soit par la liste des objets marqués pour la finalisation augmentant d'une certaine limite interne. Donc, si beaucoup d'objets sont finalisés, la phase de finalisation sera déclenchée plus souvent et plus tôt par rapport à quelques-uns seulement
  • Dans certains cas, System.gc () a déclenché une finalisation directement, mais uniquement si la référence était une vie locale et de courte durée. Cela peut être lié à la génération.

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 d'être récupéré, ce qui permet d'implémenter une sécurité intégrée si les objets avec un cycle de vie plus complexe impliquant une action de fin de vie sont traités correctement. C'est la seule raison pour laquelle je pense que cela en vaut la peine pour l'emporter.


2

Un objet devient éligible pour le garbage collection ou le GC s'il n'est pas accessible à partir de threads en direct ou de toute référence statique en d'autres termes, 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, donc 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 aucune autre référence active, les deux objets A et B seront éligibles pour la collecte des ordures. Généralement, un objet devient éligible pour le garbage collection en Java dans les cas suivants:

  1. Toutes les références de cet objet sont explicitement définies sur null, par exemple object = null
  2. L'objet est créé à l'intérieur d'un bloc et la référence sort de la portée une fois que le contrôle quitte ce bloc.
  3. Objet parent défini sur null, si un objet contient la référence d'un autre objet et lorsque vous définissez la référence de l'objet conteneur sur null, l'enfant ou l'objet contenu devient automatiquement éligible pour le garbage collection.
  4. Si un objet n'a que des références en direct via WeakHashMap, il sera éligible pour le garbage collection.

Si un finalchamp d'un objet est utilisé à plusieurs reprises au cours d'un calcul lent, et que l'objet ne sera jamais utilisé après cela, l'objet serait-il maintenu en vie jusqu'à la dernière demande du code source par le code source, ou le JIT pourrait-il copier le champ dans un variable temporaire puis abandonner l'objet avant le calcul?
supercat

@supercat: un optimiseur peut réécrire le code dans un formulaire où l'objet n'est pas créé en premier lieu; dans ce cas, il peut être finalisé juste après la fin de son constructeur, sauf si la synchronisation force un ordre entre l'utilisation de l'objet et le finaliseur.
Holger

@ Holger: Dans les cas où le JIT peut voir tout ce qui arrivera à un objet entre sa création et son abandon, je ne vois aucune raison pour que le JIT déclenche le finaliseur tôt. La vraie question serait de savoir ce que le code doit faire pour s'assurer que le finaliseur ne peut pas se déclencher dans une méthode particulière. Dans .NET, il existe une GC.KeepAlive()fonction qui ne fait que forcer le GC à supposer qu'il pourrait utiliser un objet, mais je ne connais aucune fonction de ce type en Java. On pourrait utiliser une volatilevariable à cette fin, mais utiliser une variable uniquement à cette fin semblerait un gaspillage.
supercat

@supercat: le JIT ne déclenche pas la finalisation, il arrange simplement le code pour ne pas conserver de référence, cependant, il pourrait être avantageux de mettre directement le fichier en file d'attente FinalizerReference, de sorte qu'il n'a pas besoin d'un cycle GC pour découvrir qu'il n'y a pas références. La synchronisation est suffisante pour assurer une relation qui se produit avant ; puisque la finalisation peut (en fait) s'exécuter dans un thread différent, elle est souvent formellement nécessaire de toute façon. Java 9 va ajouter Reference.reachabilityFence
Holger

@Holger: Si le JIT optimise la création d'objets, le seul Finalizeserait du tout appelé si le JIT produisait du code qui le faisait directement. Le code de synchronisation serait-il généralement attendu pour les objets qui ne s'attendent à être utilisés que dans un seul thread? Si un objet effectue une action qui doit être annulée avant d'être abandonnée (par exemple, ouvrir une connexion socket et acquérir une utilisation exclusive de la ressource à l'autre extrémité), avoir un finaliseur fermer la connexion pendant que le code utilise toujours le socket serait un désastre . Serait-il normal que le code utilise la synchronisation ...
supercat

2

La méthode de finalisation n'est pas garantie. Cette méthode est appelée lorsque l'objet devient éligible pour GC. Il existe de nombreuses situations où les objets peuvent ne pas être récupérés.


3
Incorrect. Ce que vous dites, c'est qu'un objet est finalisé lorsqu'il devient inaccessible. Il est en fait appelé lorsque la méthode est réellement collectée.
Stephen C

2

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 de détruire 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 le finalize () que méthode . Le temps d'exécution Java appelle cette méthode chaque fois qu'il est sur le point de supprimer un objet de cette classe. Dans la méthode finalize ()vous spécifiez les actions à effectuer avant de détruire un objet. Le garbage collector est périodiquement recherché pour les objets qui ne font plus référence à aucun état en cours d'exécution ou indirectement à tout autre objet avec référence. Avant la publication d'un actif, le runtime Java appelle la méthode finalize () méthode sur l'objet. Lafinalize () sous la forme générale suivante:

protected void finalize(){
    // This is where the finalization code is entered
}

Avec le mot-clé protégé , 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 le garbage collection. Il n'est pas appelé lorsqu'un objet quitte la portée, par exemple. Cela signifie que vous ne pouvez pas savoir quand, ou 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 devez pas compter sur finalize () pour un fonctionnement normal du programme.


1

Classe où nous remplaçons la méthode de finalisation

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 sont appelées

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 vidage, le GC appellera la méthode finalize

exécutez 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.


0

Java permet aux objets d'implémenter une méthode appelée finalize () qui pourrait être appelée.

La méthode finalize () est appelée si le garbage collector essaie de collecter l'objet.

Si le garbage collector ne s'exécute pas, la méthode n'est pas appelée.

Si le garbage collector ne parvient pas à collecter l'objet et essaie de l'exécuter à nouveau, la méthode n'est pas appelée la deuxième fois.

En pratique, il est peu probable que vous l'utilisiez dans de vrais projets.

Gardez juste à l'esprit qu'il pourrait ne pas être appelé et qu'il ne sera certainement pas appelé deux fois. La méthode finalize () peut s'exécuter zéro ou une fois.

Dans le code suivant, la méthode finalize () ne produit aucune sortie lorsque nous l'exécutons, car le programme se ferme avant qu'il soit nécessaire d'exécuter le garbage collector.

La source


0

finalize()est appelé juste avant la récupération de place. Il n'est pas appelé lorsqu'un objet sort du domaine. Cela signifie que vous ne pouvez pas savoir quand ni même si finalize()elle sera exécutée.

Exemple:

Si votre programme se termine avant que le ramasse-miettes ne se produise, il finalize()ne s'exécutera pas. Par conséquent, il doit être utilisé comme procédure de sauvegarde pour garantir la bonne gestion des autres ressources, ou pour des applications à usage spécial, et non comme moyen que votre programme utilise dans son fonctionnement normal.


0

Comme indiqué dans https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,

Il n'y a pas d'heure fixe à laquelle les finaliseurs doivent être exécutés car l'heure d'exécution dépend de la machine virtuelle Java (JVM). La seule garantie est que toute méthode de finalisation qui s'exécute le fera quelque temps après que l'objet associé est devenu inaccessible (détecté au cours du premier cycle de collecte des ordures) et quelque temps avant que le garbage collector ne récupère le stockage de l'objet associé (pendant le deuxième cycle du garbage collector) . L'exécution du finaliseur d'un objet peut être retardée pendant une période arbitrairement longue après que l'objet est devenu inaccessible. Par conséquent, l'invocation de fonctionnalités à temps critique telles que la fermeture de descripteurs de fichiers dans la méthode finalize () d'un objet est problématique.


-3

Essayez d'exécuter ce programme pour une meilleure compréhension

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.