web-dev-qa-db-fra.com

Quand appelle-t-on la méthode finalize () en Java?

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?

292
Rajesh Kumar J

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.

247
user7094

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.

354
Joachim Sauer
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 toujours super.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 classe 

    protected 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ée

  • finalize() 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:

68
XpiritO

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();
    }
}
22
rsp

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
}
18
Hao Deng

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:

  • L'objet n'est pas récupéré car il est toujours accessible.
  • L'objet n'est pas récupéré car le CPG ne s'exécute pas avant la fin du 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 du test.
16
Stephen C

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 nullc 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. .

10
techloris_109

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
5
user1623624

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):

  • Finalize n'est pas appelé immédiatement, le Finalizer (partie GC) possède individuellement la référence de manière indéfinie.
  • Les objets inaccessibles des pools de collecteurs de déchets par défaut
  • Finalize est appelé en gros pointant vers un détail d'implémentation qu'il existe une certaine phase où le ramasse-miettes libère les ressources.
  • L'appel de System.gc () n'entraîne souvent pas la finalisation plus fréquente des objets; il permet simplement au Finalizer de prendre plus rapidement connaissance d'un objet inaccessible.
  • La création d'un vidage de thread entraîne presque toujours le déclenchement du finaliseur en raison d'une surcharge de tas importante lors de l'exécution du vidage de tas ou d'un autre mécanisme interne.
  • La finalisation semble être liée aux exigences en matière de mémoire (libérez de la mémoire) ou à la liste des objets marqués pour la finalisation en augmentant une certaine limite interne. Donc, si vous avez finalisé de nombreux objets, la phase de finalisation sera déclenchée plus souvent et plus tôt par rapport à quelques-uns seulement.
  • Il y avait des circonstances où System.gc () a déclenché une finalisation directement, mais uniquement si la référence était locale et courte. Cela pourrait ê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 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.

4
Martin Kersten

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.

2
Amarildo

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:

  1. Toutes les références de cet objet explicitement définies sur null, par ex. objet = 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. L'objet parent est 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, l'objet null, enfant ou contenu devient automatiquement éligible pour le garbage collection.
  4. Si un objet a uniquement des références en direct via WeakHashMap, il sera éligible pour le nettoyage de la mémoire. 
2
Tushar Trivedi

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.

2
giri

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 

1
pradeep

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.

0
AyukNayr

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.

La source

0
JavaDev