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

330

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

Rajesh Kumar J
fuente
34
Solo como nota al margen: finalize está marcado como obsoleto en Java 9
Reg
si algo tiene una referencia a su objeto o incluso a la clase. finalize()y la recolección de basura no tiene ningún impacto.
ha9u63ar

Respuestas:

273

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

Según el Javadoc (que valdría la pena leer), es:

Llamado por el recolector de basura en un objeto cuando la recolección 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 siempre está accesible.

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

Paul Bellora
fuente
19
En otras palabras (solo para aclarar para futuros lectores) nunca se llama a la clase principal, ya que, cuando la clase principal cierra, no es necesario recolectar basura. El sistema operativo limpia todo lo que la aplicación utiliza de todos modos.
Mark Jeronimus
113
"no es el mejor método para usar ... a menos que haya algo específico para lo que lo necesites" - uh, esa oración se aplica al 100% de todo, por lo que no es útil. La respuesta de Joachim Sauer es mucho mejor
BT
1
@ Zom-B su ejemplo es útil para aclarar, pero solo para ser pedante, presumiblemente podría llamarse en la clase principal si la clase principal crea un hilo no demoníaco y luego regresa?
Tom G
3
Entonces, ¿cuáles son las situaciones en las finalizeque sería útil?
nbro
3
@MarkJeronimus: en realidad, eso es irrelevante. El finalize()método activado para la clase principal se invoca cuando se recolecta basura >> instancia << de la clase, no cuando finaliza el método principal. Y además, la clase principal podría ser la recolección de basura antes de que finalice la aplicación; por ejemplo, en una aplicación multiproceso donde el subproceso "principal" crea otros subprocesos y luego regresa. (En la práctica, se requeriría un cargador de clases no estándar ...)
Stephen C
379

Se finalizellama al método cuando un objeto está a punto de ser recolectado. Eso puede ocurrir en cualquier momento después de que sea 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, finalizenunca se llama). Esto puede suceder cuando el objeto nunca se vuelve elegible para gc (porque es accesible durante toda la vida útil de la JVM) o cuando no se ejecuta la recolección de basura entre el momento en que el objeto se vuelve elegible y el momento en que la JVM deja de ejecutarse (esto a menudo ocurre con simple programas de prueba).

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

Si confía en finalizeel correcto funcionamiento de su aplicación, entonces está haciendo algo mal. finalizedebe solamente ser utilizado para la limpieza de los recursos (por lo general no son de Java). Y eso es exactamente porque la JVM no garantiza que finalizese llame a ningún objeto.

Joachim Sauer
fuente
2
@Rajesh. No. No es un problema de "vida útil". Puede poner su programa en un bucle infinito (durante años), y si no se necesita el recolector de basura, nunca se ejecutará.
ChrisCantrell
55
@VikasVerma: el reemplazo perfecto no es nada: no debería necesitarlos. El único caso en el que tendría sentido es si su clase administra algún recurso externo (como una conexión TCP / IP, un archivo ... cualquier cosa que el GC de Java no pueda manejar). En esos casos, la Closableinterfaz (y la idea detrás de ella) es probablemente lo que desea: .close()cierre / descarte el recurso y solicite al usuario de su clase que lo llame en el momento adecuado. Es posible que desee agregar un finalizemétodo "solo para guardar", pero sería más una herramienta de depuración que una solución real (porque no es lo suficientemente confiable).
Joachim Sauer
44
@Dragonborn: esa es una pregunta bastante diferente y debe hacerse por separado. Hay ganchos de cierre, pero no están garantizados si la JVM se cierra inesperadamente (también se bloquea). Pero sus garantías son significativamente más fuertes que las de los finalizadores (y también son más seguras).
Joachim Sauer
44
Su último párrafo dice usarlo solo para limpiar recursos, aunque no hay garantía de que alguna vez se lo llame. ¿Está hablando este optimismo? Supongo que algo poco confiable como esto tampoco sería adecuado para limpiar recursos.
Jeroen Vannevel
2
Los finalizadores a veces pueden salvar el día ... Tuve un caso donde una biblioteca de terceros estaba usando un FileInputStream, nunca cerrándolo. Mi código estaba llamando al código de la biblioteca, y luego traté de mover el archivo, fallando porque todavía estaba abierto. Tuve que forzar la llamada System.gc()para invocar FileInputStream :: finalize (), luego pude mover el archivo.
Elist
73
protected void finalize() throws Throwable {}
  • cada clase hereda el finalize()método de java.lang.Object
  • el recolector de basura llama al método cuando determina que no existen más referencias al objeto
  • el método Finalizar objeto no realiza acciones, pero puede ser anulado por cualquier clase
  • normalmente debería anularse para limpiar recursos que no sean Java, es decir, cerrar un archivo
  • si se anula finalize(), es una buena práctica de programación usar una instrucción try-catch-finally y llamar siempre super.finalize(). Esta es una medida de seguridad para garantizar que no se pierda inadvertidamente el cierre de un recurso utilizado por los objetos que llaman a la clase

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
  • cualquier excepción lanzada finalize()durante la recolección de basura detiene la 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:

XpiritO
fuente
25
El artículo de JavaWorld al que se vincula es de 1998, y tiene algunos consejos interesantes, particularmente la sugerencia de que se llame a System.runFinalizersOnExit () para garantizar que los finalizadores se ejecuten antes de que la JVM salga. Ese método está actualmente en desuso, con el comentario 'Este método es inherentemente inseguro. Puede provocar que los finalizadores sean llamados a objetos vivos mientras que otros hilos manipulan simultáneamente esos objetos, lo que resulta en un comportamiento errático o un punto muerto '. Entonces no voy a estar haciendo eso.
Greg Chabala
3
Como runFinalizerOnExit () NO es seguro para subprocesos, lo que uno podría hacer es Runtime.getRuntime (). AddShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); en el constructor de la clase.
Ustaman Sangat
2
@Ustaman Sangat Esa es una forma de hacerlo, pero recuerde que esto establece una referencia a su instancia desde shutdownHook, lo que garantiza que su clase nunca se recolecte basura. En otras palabras, es una pérdida de memoria.
pieroxy
1
@pieroxy, si bien estoy de acuerdo con todos los demás aquí con respecto a no usar finalize () para nada, no veo por qué tendría que haber una referencia desde el gancho de apagado. Uno podría tener una referencia suave.
Ustaman Sangat
25

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

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

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

Echa un vistazo a Effective Java, segunda edición, página 27. Artículo 7: Evita los finalizadores

Los finalizadores son impredecibles, a menudo peligrosos y generalmente innecesarios. nunca haga 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
}
Hao Deng
fuente
3
o use try-with-resources
Gabriel Garcia
3
Esto supone que la vida útil de un objeto está dentro del alcance de una función. Lo cual, por supuesto, no es el caso al que se refiere el OP, ni es el caso que básicamente cualquier persona necesita. Piense en "conteo de referencia del valor de retorno del motor de caché". Desea liberar la entrada de caché cuando se libera la última referencia, pero no sabe cuándo se libera la última referencia. finalize () puede disminuir un recuento de referencias, por ejemplo ... pero si requiere que sus usuarios llamen explícitamente a una función gratuita, está solicitando pérdidas de memoria. por lo general sólo lo hago tanto (+ función de doble control de liberación de finalización ...) ...
Erik Aronesty
16

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

El método de finalización se llamará después de que el GC detecte que ya no se puede acceder al objeto, y antes de que realmente reclame la memoria utilizada por el objeto.

  • Si un objeto nunca se vuelve inalcanzable, finalize()nunca se lo llamará.

  • Si el GC no se ejecuta, es finalize()posible que nunca se llame. (Normalmente, el GC solo se ejecuta cuando la JVM decide que es probable que haya suficiente basura para 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. (Los GC de Java suelen ser recopiladores "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 generalmente ocurre de forma asíncrona con el GC normal.

(La especificación JVM en realidad permite que una JVM nunca ejecute finalizadores ... siempre que no reclame 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 deben hacerse en un marco de tiempo definido. Es "mejor práctica" no usarlos en absoluto. Debería haber una forma mejor (es decir, más confiable) de hacer lo que sea que intente hacer en el finalize()método.

El único uso legítimo para la finalización es limpiar 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 ...)


Creé una clase de prueba que escribe en un archivo cuando se llama al método finalize () al anularlo. No se ejecuta ¿Alguien puede decirme la razón por la que 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 es basura recolectada porque el GC no se ejecuta antes de que finalice su prueba.
  • El GC encuentra el objeto y el GC lo coloca en la cola de finalización, pero la finalización no se completa antes de que finalice la prueba.
Stephen C
fuente
10

Dado que existe una incertidumbre en la llamada del método finalize () por JVM (no estoy seguro de si se ejecutará o no finalize () que se anula), para fines de estudio, la mejor manera de observar lo que sucede cuando se llama a finalize () es obligar 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 intentamos llamarlo creando nuevos objetos, no hay certeza de su llamada. Entonces, con certeza, creamos un nullobjeto cque obviamente no tiene uso futuro, por lo tanto, vemos la cllamada de finalización del objeto .

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, existe la incertidumbre de que b sea borrado o no por JVM ya que "Método de finalización llamado en la clase Bike ..." no se imprime.

techloris_109
fuente
10
Llamar System.gc();no garantiza que la recolección de basura se ejecutará realmente.
Simon Forsberg
3
Tampoco se garantiza qué tipo de colección se ejecutará. Relevante ya que la mayoría de los GC de Java son colectores "generacionales".
Stephen C
5

finalize imprimirá el conteo 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. La siguiente salida muestra que el gc se ejecutó por primera vez cuando el recuento 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
usuario1623624
fuente
4

Habiendo luchado con los métodos del finalizador últimamente (para deshacerse de los grupos de conexiones durante las pruebas), debo decir que el finalizador carece de muchas cosas. Usando VisualVM para observar y usando referencias débiles para rastrear la interacción real, descubrí que las siguientes cosas son ciertas en un entorno Java 8 (Oracle JDK, Ubuntu 15):

  • Finalizar no se llama inmediatamente, el Finalizador (parte GC) posee individualmente la referencia de forma esquiva
  • El recolector de basura predeterminado agrupa objetos inalcanzables
  • Se llama Finalizar en masa para indicar un detalle de implementación de que hay una cierta fase en la que el recolector de basura libera los recursos.
  • Llamar a System.gc () a menudo no da como resultado que los objetos se finalicen con más frecuencia, solo hace que el Finalizador se dé cuenta de un objeto inalcanzable más rápidamente
  • La creación de un volcado de subprocesos casi siempre provoca la activación del finalizador debido a una alta sobrecarga de almacenamiento dinámico durante la realización del volcado de almacenamiento dinámico o algún otro mecanismo interno
  • Las costuras de finalización están unidas por los requisitos de memoria (liberar más memoria) o por la lista de objetos que se marcan para el crecimiento de finalización de un cierto límite interno. Entonces, si tiene muchos objetos finalizados, la fase de finalización se activará con más frecuencia y antes en comparación con solo unos pocos
  • Hubo circunstancias en que System.gc () activó una finalización directamente, pero solo si la referencia era una vida local y corta. Esto podría estar relacionado con la generación.

Pensamiento final

El método de finalización no es confiable, pero solo se puede usar para una cosa. Puede asegurarse de que un objeto se cerró o se eliminó antes de que se recogiera la basura, lo que permite implementar una caja fuerte a prueba de fallas 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 razón por la que puedo pensar que hace que valga la pena para anularlo.

Martin Kersten
fuente
2

Un objeto se vuelve elegible para la recolección de basura o GC si no se puede acceder desde ningún subproceso en vivo o cualquier referencia estática, en otras palabras, puede decir que un objeto se vuelve elegible para la recolección de basura si todas sus referencias son nulas. Las dependencias cíclicas no se cuentan como referencia, por lo que si el Objeto A tiene referencia del objeto B y el objeto B tiene referencia del Objeto A y no tienen ninguna otra referencia en vivo, entonces los Objetos A y B serán elegibles para la recolección de basura. En general, un objeto se vuelve 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 nulo, por ejemplo, objeto = nulo
  2. El objeto se crea dentro de un bloque y la referencia sale del alcance una vez que el control sale de ese bloque.
  3. El objeto primario se establece en nulo, si un objeto contiene la referencia de otro objeto y cuando establece la referencia del objeto contenedor nulo, el objeto secundario o contenido se convierte automáticamente en elegible para la recolección de basura.
  4. Si un objeto solo tiene referencias en vivo a través de WeakHashMap, será elegible para la recolección de basura.
Tushar Trivedi
fuente
Si el finalcampo de un objeto se usa repetidamente durante un cálculo lento, y el objeto nunca se usará después de eso, ¿se mantendría vivo hasta el último momento en que el código fuente solicite el campo, o podría el JIT copiar el campo a un variable temporal y luego abandonar el objeto antes del cálculo?
supercat
@supercat: un optimizador puede volver a escribir código en un formulario donde el objeto no se crea en primer lugar; en ese caso, puede finalizar justo después de que termine su constructor, a menos que la sincronización fuerce un orden entre el uso del objeto y el finalizador.
Holger
@Holger: En los casos en que el JIT puede ver todo lo que le sucederá a un objeto entre su creación y su abandono, no veo ninguna razón para que el JIT dispare el finalizador antes de tiempo. La verdadera pregunta sería qué código debe hacer para garantizar que el finalizador no pueda dispararse dentro de un método en particular. En .NET hay una GC.KeepAlive()función que no hace nada excepto forzar al GC a suponer que podría usar un objeto, pero no sé de tal función en Java. Se podría usar una volatilevariable para ese propósito, pero usar una variable únicamente para tal propósito parecería un desperdicio.
supercat
@supercat: El JIT no dispara la finalización, solo organiza el código para que no mantenga una referencia, sin embargo, podría ser beneficioso poner en cola directamente FinalizerReference, para que no necesite un ciclo GC para descubrir que no hay referencias La sincronización es suficiente para garantizar una relación antes de que suceda ; Dado que la finalización puede (en realidad está) ejecutándose en un hilo diferente, a menudo es formalmente necesario de todos modos. Java 9 va a agregar Reference.reachabilityFence...
Holger
@Holger: Si el JIT optimiza la creación de objetos, lo único Finalizeque se llamaría sería si el JIT produjera código que lo hiciera directamente. ¿Se esperaría típicamente el código de sincronización para los objetos que solo esperan ser utilizados en un solo hilo? Si un objeto realiza alguna acción que necesita deshacerse antes de abandonarlo (por ejemplo, abrir una conexión de socket y adquirir un uso exclusivo del recurso en el otro extremo), hacer que un finalizador cierre la conexión mientras el código todavía está usando el socket sería un desastre . ¿Sería normal que el código use la sincronización ...
Supercat
2

el método de finalización no está garantizado. Este método se llama cuando el objeto se vuelve elegible para GC. Hay muchas situaciones en las que los objetos pueden no ser basura recolectada.

giri
fuente
3
Incorrecto. Lo que está diciendo es que un objeto se finaliza cuando se vuelve inalcanzable. En realidad se llama cuando el método se recopila realmente.
Stephen C
2

A veces, cuando se destruye, un objeto debe realizar una acción. Por ejemplo, si un objeto tiene un recurso no java, como un identificador 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 "finalización". Al finalizarlo, puede definir acciones específicas que se producen cuando un objeto está a punto de eliminarse del recolector de basura. Para agregar un finalizador a una clase, simplemente defina el método finalize () . El tiempo de ejecución de Java llama a este método cuando está a punto de eliminar un objeto de esa clase. Dentro del método finalize ()Usted especifica acciones a realizar antes de destruir un objeto. El recolector de basura se busca periódicamente objetos que ya no se refieren a ningún estado en ejecución o indirectamente a cualquier otro objeto con referencia. Antes de liberar un activo, el tiempo de ejecución de Java llama al método finalize () en el objeto. El método finalize () tiene la siguiente forma general:

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

Con la palabra clave protegida , se impide el acceso a finalize () por código fuera de su clase. Es importante comprender que finalize () se llama justo antes de la recolección de basura. No se llama cuando un objeto abandona el ámbito, por ejemplo. Significa que no puede saber cuándo o si se ejecutará finalize () . 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.

Amarildo
fuente
1

Clase donde anulamos el método de finalización

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 finalizar el método se llaman

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

cuando la memoria se sobrecarga con objetos de volcado, el gc llamará al método finalize

ejecute y vea la consola, donde no encuentra el método de finalización que se llama con frecuencia, cuando la memoria se sobrecarga, se llamará al método de finalización.

pradeep
fuente
0

Java permite que los objetos implementen un método llamado finalize () que podría llamarse.

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

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

Si el recolector de basura no puede recolectar el objeto e intenta ejecutarlo nuevamente, el método no se llama por segunda vez.

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

Solo tenga en cuenta que es posible que no se llame y que definitivamente no se llamará dos veces. El método finalize () podría ejecutarse cero o una vez.

En el siguiente código, el método finalize () no produce resultados cuando lo ejecutamos, ya que el programa se cierra antes de que sea necesario ejecutar el recolector de basura.

Fuente

JavaDev
fuente
0

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

Ejemplo:

Si su programa finaliza antes de que ocurra el recolector de basura, finalize()no se ejecutará. Por lo tanto, debe usarse como procedimiento de respaldo para garantizar el manejo adecuado de otros recursos, o para aplicaciones de uso especial, no como el medio que su programa usa en su funcionamiento normal.

AyukNayr
fuente
0

Como se señaló en https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,

No hay un tiempo fijo en el que se deben ejecutar los finalizadores porque el tiempo de ejecución depende de la máquina virtual Java (JVM). La única garantía es que cualquier método finalizador que se ejecute lo hará en algún momento después de que el objeto asociado se haya vuelto inalcanzable (detectado durante el primer ciclo de recolección de basura) y en algún momento antes de que el recolector de basura reclame el almacenamiento del objeto asociado (durante el segundo ciclo del recolector de basura) . La ejecución del finalizador de un objeto puede retrasarse durante un tiempo arbitrariamente largo después de que el objeto se vuelva inalcanzable. En consecuencia, invocar una funcionalidad de tiempo crítico, como cerrar identificadores de archivos en el método finalize () de un objeto, es problemático.

Utkarsh Gupta
fuente
-3

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();
            }
     }
}
usuario3836455
fuente