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?
330
finalize()
y la recolección de basura no tiene ningún impacto.Respuestas:
En general, es mejor no confiar en
finalize()
hacer ninguna limpieza, etc.Según el Javadoc (que valdría la pena leer), es:
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.fuente
finalize
que sería útil?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 ...)Se
finalize
llama 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,
finalize
nunca 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
finalize
en 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
finalize
el correcto funcionamiento de su aplicación, entonces está haciendo algo mal.finalize
debe 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 quefinalize
se llame a ningún objeto.fuente
Closable
interfaz (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 unfinalize
mé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).System.gc()
para invocar FileInputStream :: finalize (), luego pude mover el archivo.citado de: http://www.janeg.ca/scjp/gc/finalize.html
También puedes consultar este artículo:
fuente
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 quefinalize
se llame al método durante el tiempo de vida de la aplicación.Lo que probablemente desea es una combinación de
finally
y un método de limpieza, como en:fuente
Echa un vistazo a Effective Java, segunda edición, página 27. Artículo 7: Evita los finalizadores
Para terminar un recurso, use try-finally en su lugar:
fuente
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 ...)Es difícil de decir, pero hay algunas posibilidades:
fuente
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
null
objetoc
que obviamente no tiene uso futuro, por lo tanto, vemos lac
llamada de finalización del objeto .Ejemplo
Salida
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.
fuente
System.gc();
no garantiza que la recolección de basura se ejecutará realmente.finalize imprimirá el conteo para la creación de la clase
principal
Como puedes ver. La siguiente salida muestra que el gc se ejecutó por primera vez cuando el recuento de clases es 36.
fuente
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):
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.
fuente
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:
fuente
final
campo 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?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 unavolatile
variable para ese propósito, pero usar una variable únicamente para tal propósito parecería un desperdicio.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 agregarReference.reachabilityFence
...Finalize
que 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 ...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.
fuente
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:
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.
fuente
Clase donde anulamos el método de finalización
Las posibilidades de finalizar el método se llaman
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.
fuente
Fuente
fuente
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 sifinalize()
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.fuente
Como se señaló en https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,
fuente
Intente ejecutar este programa para comprender mejor
fuente