¿Cuándo se llama al método finalize() en Java?


Necesito saber cuándo se llama al método finalize() en JVM. Creé una clase de prueba que escribe en un archivo cuando se llama al método finalize() sobrescribiéndolo. No se ejecuta. ¿Puede alguien decirme la razón por la que no se está ejecutando?

Author: Vipin Jain, 2010-03-24

16 answers

En general, es mejor no confiar en finalize() para hacer cualquier limpieza, etc.

De acuerdo con el Javadoc (que valdría la pena leer), es:

Llamado por el recolector de basura en un objeto cuando el recolector de basura determina que no hay más referencias al objeto.

Como señaló Joachim, esto nunca puede suceder en la vida de un programa si el objeto es siempre accesible.

Además, el recolector de basura no está garantizado para ejecutar en cualquier momento específico. En general, lo que estoy tratando de decir es que finalize() probablemente no sea el mejor método para usar en general a menos que haya algo específico para lo que lo necesite.

 236
Author: Paul Bellora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-17 18:05:21

El método finalize se llama cuando un objeto está a punto de recoger basura. Eso puede ser en cualquier momento después de que se haya convertido en elegible para la recolección de basura.

Tenga en cuenta que es completamente posible que un objeto nunca se recolecte basura (y por lo tanto finalize nunca se llame). Esto puede suceder cuando el objeto nunca se convierte en elegible para gc (porque es accesible durante toda la vida útil de la JVM) o cuando no se ejecuta ninguna recolección de basura entre el momento en que el objeto se convierte en elegible y el tiempo que la JVM deja de ejecutarse (esto a menudo ocurre con programas de prueba simples).

Hay formas de decirle a la JVM que ejecute finalize en objetos a los que aún no se le haya llamado, pero usarlos tampoco es una buena idea (las garantías de ese método tampoco son muy fuertes).

Si confías en finalize para el correcto funcionamiento de tu aplicación, entonces estás haciendo algo mal. finalize debería usar solo para la limpieza de recursos (normalmente no Java). Y eso es exactamente porque la JVM no garantiza que finalize sea invocado en ningún objeto.

 341
Author: Joachim Sauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-09 10:07:58
protected void finalize() throws Throwable {}
  • cada clase hereda el método finalize() de Java.lang.Objeto
  • el método es llamado por el recolector de basura cuando determina no más referencias al objeto exist
  • el método Object finalize no realiza ninguna acción, pero puede ser anulado por cualquier clase
  • normalmente debe ser anulado para limpiar los recursos no Java ie cierre un archivo
  • Si se reemplaza finalize() es una buena práctica de programación para use un try-catch - finally declaración y a siempre llame super.finalize(). Este es una medida de seguridad para garantizar que lo haga no se pierda inadvertidamente el cierre de una recurso utilizado por los objetos que llaman clase

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
    
  • Cualquier excepción lanzada por finalize() durante la recolección de basura detiene finalización, pero por lo demás se ignora

  • finalize() nunca se ejecuta más de una vez en ningún objeto

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

También puedes consultar este artículo:

 66
Author: XpiritO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-24 09:31:09

El método Java finalize() no es un destructor y no debe usarse para manejar la lógica de la que depende su aplicación. La especificación Java indica que no hay garantía de que el método finalize sea llamado durante el tiempo de vida de la aplicación.

Lo que desea es una combinación de finally y un método de limpieza, como en:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

    if (null != myObj) {
        myObj.cleanup();
    }
}
 21
Author: rsp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-24 15:29:24

Echa un vistazo a Effective Java, 2nd edition página 27. Punto 7: Evitar los finalizadores

Los finalizadores son impredecibles, a menudo peligrosos y generalmente innecesarios. nunca hagas nada crítico en un finalizador. nunca dependa de un finalizador para actualizar el estado crítico persistente.

Para terminar un recurso, use try-finally en su lugar:

// 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
}
 19
Author: Hao Deng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-12 05:20:38

¿Cuándo se llama el método finalize() en Java?

El método finalize se llamará después de que el GC detecte que el objeto ya no es accesible, y antes de que realmente recupere la memoria utilizada por el objeto.

  • Si un objeto nunca se vuelve inalcanzable, finalize() nunca será llamado sobre él.

  • Si el GC no se ejecuta, es posible que nunca se llame a finalize(). (Normalmente, el GC solo se ejecuta cuando la JVM decide que es probable que haya suficiente basura para haz que valga la pena.)

  • Puede tomar más de un ciclo de GC antes de que el GC determine que un objeto específico es inalcanzable. (Java GCs son típicamente colectores "generacionales"...)

  • Una vez que el GC detecta que un objeto es inalcanzable y finalizable, se coloca en una cola de finalización. La finalización ocurre típicamente asincrónicamente con el GC normal.

(La especificación JVM en realidad permite una JVM para nunca ejecutar finalizadores ... siempre que no recupere el espacio utilizado por los objetos. Una JVM que se implementó de esta manera sería lisiada / inútil, pero este comportamiento está "permitido".)

El resultado es que no es prudente confiar en la finalización para hacer cosas que tienen que hacerse en un marco de tiempo definido. Es una "mejor práctica" no usarlos en absoluto. Debería haber una manera mejor (es decir, más confiable) de hacer lo que sea que esté tratando de hacer en el método finalize().

El único legítimo el uso para la finalización es limpiar los recursos asociados con objetos que se han perdido por el código de la aplicación. Incluso entonces, debe intentar escribir el código de la aplicación para que no pierda los objetos en primer lugar. (Por ejemplo, use Java 7 + try-with-resources para asegurarse de que close() siempre se llame ...)


He creado una clase de prueba que escribe en un archivo cuando se llama al método finalize() sobrescribiéndolo. No se ejecuta. ¿Puede alguien decirme el ¿por qué no se está ejecutando?

Es difícil de decir, pero hay algunas posibilidades:

  • El objeto no es basura recolectada porque todavía es accesible.
  • El objeto no se recolecta porque el GC no se ejecuta antes de que finalice su prueba.
  • El objeto es encontrado por el GC y colocado en la cola de finalización por el GC, pero la finalización no se completa antes de que finalice su prueba.
 16
Author: Stephen C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-22 00:42:09

Dado que hay una incertidumbre en la llamada del método finalize() por JVM (no está seguro de si finalize() que se anula se ejecutará o no), para fines de estudio, la mejor manera de observar lo que sucede cuando se llama a finalize (), es forzar a la JVM a llamar a la recolección de basura por comando System.gc().

Específicamente, se llama a finalize() cuando un objeto ya no está en uso. Pero cuando tratamos de llamarlo mediante la creación de nuevos objetos no hay certeza de su llamada. Así que para la certeza creamos un objeto null c que obviamente no tiene uso futuro, por lo tanto vemos la llamada de finalización del objeto c.

Ejemplo

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

Salida

    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.

Nota - Incluso después de imprimir hasta 70 y después de lo cual el objeto b no se está utilizando en el programa, hay incertidumbre de que b se borra o no por JVM ya que "Llamado método finalizar en Bicicleta de clase..."no está impreso.

 9
Author: techloris_109,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-10 08:08:34

Finalize imprimirá el recuento para la creación de la clase.

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

Principal

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

Como puedes ver. El siguiente out put muestra que el gc se ejecutó por primera vez cuando el conteo de clases es 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
Author: user1623624,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-24 23:40:41

Después de haber luchado con los métodos de finalizer últimamente (con el fin de deshacerse de los grupos de conexión durante las pruebas), tengo que decir que finalizer carece de muchas cosas. Usando VisualVM para observar, así como usando referencias débiles para rastrear la interacción real, encontré que las siguientes cosas son ciertas en un entorno Java 8 (Oracle JDK, Ubuntu 15):

  • Finalize no se llama inmediatamente el Finalizer (parte GC) posee individualmente la referencia elusively
  • Los repositorios de Recolectores de Basura predeterminados objetos inalcanzables
  • Finalize se llama en masa apuntando a un detalle de implementación que hay una cierta fase en la que el recolector de basura libera los recursos.
  • Sistema de llamada.gc () a menudo no resulta en que los objetos se finalicen más a menudo, solo resulta en que el finalizador se dé cuenta de un objeto inalcanzable más rápidamente
  • La creación de un volcado de hilo casi siempre resulta en la activación del finalizador debido a la alta sobrecarga de montón durante la realización del volcado de montón o algún otro mecanismo interno
  • La finalización se une a los requisitos de memoria (liberar más memoria) o a la lista de objetos que se marcan para la finalización que crece de un cierto límite interno. Por lo tanto, si tiene muchos objetos finalizando, la fase de finalización se activará con más frecuencia y antes en comparación con solo unos pocos
  • Hubo circunstancias de un Sistema.gc () activó un finalizar directamente, pero solo si la referencia era local y de corta vida. Esto podría ser relacionados con la generación.

Pensamiento final

El método Finalize no es fiable, pero solo se puede usar para una cosa. Puede asegurarse de que un objeto fue cerrado o desechado antes de que se recogiera basura, lo que hace posible implementar un sistema a prueba de fallos si los objetos con un ciclo de vida más complejo que involucra una acción de fin de vida se manejan correctamente. Esa es la única razón que puedo pensar que hace que valga la pena para anularlo.

 4
Author: Martin Kersten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-25 11:08:13

El método Finalize no está garantizado.Este método se llama cuando el objeto se convierte en elegible para GC. Hay muchas situaciones en las que los objetos pueden no ser basura recolectada.

 3
Author: giri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-14 05:35:53

Un objeto se convierte en elegible para la recolección de basura o GC si no es accesible desde ningún hilo vivo o refrencias estáticas en otras palabras, puede decir que un objeto se convierte en elegible para la recolección de basura si todas sus referencias son null. Las dependencias cíclicas no se cuentan como referencia, por lo que si el Objeto A tiene referencia al objeto B y el objeto B tiene referencia al Objeto A y no tienen ninguna otra referencia en vivo, ambos Objetos A y B serán elegibles para la recolección de basura. Generalmente un object se convierte en elegible para la recolección de basura en Java en los siguientes casos:

  1. Todas las referencias de ese objeto se establecen explícitamente en null, por ejemplo, object = null
  2. El objeto se crea dentro de un bloque y la referencia sale del ámbito una vez que el control sale de ese bloque.
  3. Objeto padre establecido en null, si un objeto contiene la referencia de otro objeto y cuando se establece la referencia del objeto contenedor null, el objeto hijo o contenido se convierte automáticamente en elegible para la recolección de basura.
  4. Si un el objeto solo tiene referencias vivas a través de WeakHashMap será elegible para la recolección de basura.
 2
Author: Tushar Trivedi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-09 12:27:55

A veces, cuando se destruye, un objeto debe realizar una acción. Por ejemplo, si un objeto tiene un recurso que no es java, como un controlador de archivo o una fuente, puede verificar que estos recursos se liberen antes de destruir un objeto. Para gestionar tales situaciones, java ofrece un mecanismo llamado "finalizing". Al finalizarlo, puede definir acciones específicas que ocurren cuando un objeto está a punto de ser eliminado del recolector de basura. Para añadir un finalizer a una clase simplemente defina el finalize () método. Java execution time llama a este método cada vez que está a punto de eliminar un objeto de esa clase. Dentro del método finalize () se especifican las acciones a realizar antes de destruir un objeto. El recolector de basura se busca periódicamente para los objetos que ya no se refieren a ningún estado en ejecución o indirectamente cualquier otro objeto con referencia. Antes de liberar un recurso, el tiempo de ejecución de Java llama al método finalize() en el objeto. El método finalize () tiene el siguiente formulario general:

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

Con la palabra clave protected, se impide el acceso a finalize() por código fuera de su clase. Es importante entender que finalize () se llama justo antes de la recolección de basura. No se llama cuando un objeto sale del ámbito, por ejemplo. Significa que no puede saber cuándo, o si, finalize () se ejecutará. Como resultado, el programa debe proporcionar otros medios para liberar recursos del sistema u otros recursos utilizados por el objeto. No debe confiar en finalize() para la ejecución normal del programa.

 2
Author: Amarildo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-02 20:19:10

Clase donde sobrescribimos el método 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");
    }
}

Las posibilidades de que se llame al método finalize

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

Cuando la memoria está sobrecargada con objetos de volcado, gc llamará al método finalize

Ejecute y vea la consola, donde no encuentra que el método finalize se llame con frecuencia, cuando la memoria se sobrecarga, se llamará al método finalize.

 1
Author: pradeep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-01 12:41:09

Java permite a los objetos implementar un método llamado finalize() eso podría ser llamado.

Se llama al método Finalize() si el recolector de basura intenta recoge el objeto.

Si el recolector de basura no se ejecuta, no se llama al método.

Si el recolector de basura falla al recolectar el objeto e intenta ejecutar de nuevo, el método no se llama en la segunda vez.

En la práctica, usted es altamente es poco probable que lo use en proyectos reales.

Solo tenga en cuenta que podría no ser llamado y que definitivamente no me llamarán dos veces. El método finalize () podría ejecutar cero o uno tiempo.

En el siguiente código, el método finalize() no produce salida cuando ejecutarlo ya que el programa sale antes de que haya necesidad de ejecutar el recolector de basura.

Fuente

 0
Author: JavaDev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-25 12:04:36

finalize() se llama justo antes de la recolección de basura. No se llama cuando un objeto sale del alcance. Esto significa que no puede saber cuándo o incluso si finalize() se ejecutará.

Ejemplo:

Si su programa termina antes de que ocurra el recolector de basura, entonces finalize() no se ejecutará. Por lo tanto, debe ser utilizado como procedimiento de copia de seguridad para garantizar el manejo adecuado de otros recursos, o para aplicaciones de uso especial, no como el medio que su programa utiliza en su funcionamiento normal.

 0
Author: AyukNayr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-17 07:27:42

Intente ejecutar este programa para comprender mejor

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();
            }
     }
}
 -3
Author: user3836455,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-17 16:02:03