Según el Java efectivo de Joshua Bloch (segunda edición), hay dos escenarios cuando finalize()
es útil:
Una es actuar como una "red de seguridad" en caso de que el propietario de un objeto se olvide de llamar a su método de terminación explícito. Si bien no hay garantía de que se invoque al finalizador de inmediato, puede ser mejor liberar el recurso tarde que nunca, en aquellos casos (con suerte raros) cuando el cliente no llama al método de terminación explícito. Pero el finalizador debe registrar una advertencia si encuentra que el recurso no se ha terminado
Un segundo uso legítimo de finalizadores se refiere a objetos con pares nativos. Un par nativo es un objeto nativo al que un objeto normal delega a través de métodos nativos. Debido a que un par nativo no es un objeto normal, el recolector de basura no lo sabe y no puede reclamarlo cuando se reclama su par Java. Un finalizador es un vehículo apropiado para realizar esta tarea, suponiendo que el par nativo no tenga recursos críticos. Si el par nativo tiene recursos que deben terminarse rápidamente, la clase debe tener un método de terminación explícito, como se describió anteriormente. El método de terminación debe hacer lo que sea necesario para liberar el recurso crítico.
Para más información, consulte el Artículo 7, página 27.
Los finalizadores son importantes para la gestión de los recursos nativos. Por ejemplo, su objeto podría necesitar asignar un WidgetHandle desde el sistema operativo usando una API que no sea Java. Si no liberas ese WidgetHandle cuando tu objeto es GC'd, vas a perder WidgetHandles.
Lo importante es que los casos de "finalizador nunca se llaman" se descomponen simplemente:
En los tres casos, no tiene una fuga nativa (en virtud del hecho de que su programa ya no se está ejecutando) o ya tiene una fuga no nativa (si sigue asignando objetos administrados sin que sean GC'd).
La advertencia "no confíe en que se llame al finalizador" se trata realmente de no usar finalizadores para la lógica del programa. Por ejemplo, no desea realizar un seguimiento de cuántos de sus objetos existen en todas las instancias de su programa incrementando un contador en un archivo en algún lugar durante la construcción y decrementándolo en un finalizador, porque no hay garantía de que sus objetos finalizado, este contador de archivos probablemente nunca volverá a 0. Este es realmente un caso especial del principio más general de que no debe depender de que su programa termine normalmente (fallas de energía, etc.).
Sin embargo, para la administración de recursos nativos, los casos en los que el finalizador no se ejecuta corresponden a casos en los que no le importa si no se ejecuta.
fuente
close()
no se llama antes de que sea inalcanzable)El propósito de este método se explica en la documentación de la API de la siguiente manera:
Si también está interesado en las razones por las cuales los diseñadores de idiomas han elegido que "el objeto se descarta irrevocablemente" ( basura recolectada ) de la manera que está más allá del control del programador de aplicaciones ("nunca debemos confiar"), esto se ha explicado en una respuesta a pregunta :
La cita anterior, a su vez, se tomó de la documentación oficial sobre los objetivos de diseño de Java , es decir, se puede considerar una referencia autorizada que explica por qué los diseñadores de lenguaje Java decidieron de esta manera.
Para una discusión más detallada y agnóstica del lenguaje de esta preferencia, consulte la sección 9.6 de OOSC Gestión automática de memoria (en realidad, no solo vale la pena leer esta sección, sino todo el capítulo 9 si está interesado en cosas como esa). Esta sección se abre con una declaración inequívoca:
fuente
Los finalizadores existen porque se esperaba que fueran un medio eficaz para garantizar que las cosas se limpien (aunque en la práctica no lo son), y porque cuando se inventaron, mejores medios para garantizar la limpieza (como referencias fantasmas y pruebas) -resources) aún no existía. En retrospectiva, Java probablemente sería mejor si el esfuerzo dedicado a implementar su instalación de "finalización" se hubiera dedicado a otros medios de limpieza, pero eso no estuvo claro durante el tiempo en que Java se desarrolló inicialmente.
fuente
CAVEAT: Puede que esté desactualizado, pero así lo entiendo hace unos años:
En general, no hay garantía de cuándo se ejecuta un finalizador, o incluso si se ejecuta en absoluto, aunque algunas JVM le permitirán solicitar un GC completo y una finalización antes de que el programa salga (lo que, por supuesto, significa que el programa lleva más tiempo). para salir, y que no es el modo de operación predeterminado).
Y se sabía que algunos GC retrasaban o evitaban explícitamente los objetos de GC que tenían finalizadores, con la esperanza de que esto produjera un mejor rendimiento en los puntos de referencia.
Desafortunadamente, estos comportamientos entran en conflicto con las razones originales por las que se recomendaron los finalizadores, y en su lugar han alentado el uso de métodos de apagado explícitamente llamados.
Si tiene un objeto que realmente tiene que limpiarse antes de ser descartado, y si realmente no puede confiar en que los usuarios lo hagan, puede valer la pena considerar un finalizador. Pero en general, hay buenas razones por las que no las ve tan a menudo en el código Java moderno como lo hizo en algunos de los primeros ejemplos.
fuente
La Guía de estilo de Java de Google tiene algunos sabios consejos sobre el tema:
fuente
PhantomReference
y en suReferenceQueue
lugar.PhantomReference
es una mejor solución. Los finalizadores son una verruga que quedó de los primeros días de Java, y los me gustaObject.clone()
y los tipos sin formato son parte del lenguaje que mejor se olvida.La especificación del lenguaje Java (Java SE 7) establece:
fuente