¿Por qué se incluye el método de finalización en Java?

44

De acuerdo con esta publicación , nunca debemos confiar en el método de finalización que se llamará. Entonces, ¿por qué Java lo incluyó en el lenguaje de programación?

Parece una decisión terrible incluir en cualquier lenguaje de programación una función a la que pueda ser llamada.

    
pregunta patstuart 25.06.2014 - 19:07

7 respuestas

41

Según Effective Java (Segunda edición) de Joshua Bloch, hay dos escenarios cuando finalize() es útil:

  1.   

    Uno es actuar como una "red de seguridad" en caso de que el propietario de un objeto se olvide   para llamar a su método de terminación explícita. Si bien no hay garantía   que el finalizador se invoque rápidamente, puede ser mejor liberar   el recurso tardío que nunca, en aquellos (con suerte raros) casos en los que   el cliente no puede llamar al método de terminación explícito. Pero el   el finalizador debe registrar una advertencia si encuentra que el recurso no tiene   sido terminado

  2.   

    Un segundo uso legítimo de los finalizadores concierne a los objetos con nativos   compañeros Un par nativo es un objeto nativo al cual un objeto normal   Los delegados a través de métodos nativos. Porque un par nativo no es un normal   objeto, el recolector de basura no lo sabe y no puede reclamar   Es cuando se reclama su par de Java. Un finalizador es un apropiado   vehículo para realizar esta tarea, asumiendo que el par nativo no tiene   recursos críticos. Si el par nativo tiene recursos que deben ser   terminada puntualmente, la clase debe tener una terminación explícita   método, como se describe anteriormente. El método de terminación debe hacer lo que sea   es necesario para liberar el recurso crítico.

Para obtener más información, consulte el Artículo 7, página 27.

    
respondido por el bbalchev 25.06.2014 - 22:38
55

Los finalizadores son importantes para la administración de recursos nativos. Por ejemplo, su objeto podría necesitar asignar un WidgetHandle desde el sistema operativo utilizando una API que no sea de Java. Si no liberas esa WidgetHandle cuando tu objeto es GC'd, perderás WidgetHandles.

Lo importante es que los casos de "el finalizador nunca se llama" se descomponen de manera simple:

  1. El programa se apaga rápidamente
  2. El objeto "vive para siempre" durante la vida útil del programa
  3. La computadora se apaga / su proceso es eliminado por el SO / etc

En los tres casos, o bien no tiene una fuga nativa (debido a que su programa ya no se está ejecutando), o ya tiene un no -fuga nativa (si continúa asignando objetos administrados sin que sean GC'd).

La advertencia "no confíe en que se llame al finalizador" realmente se refiere a no usar los 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 al incrementar un contador en un archivo en algún lugar durante la construcción y disminuirlo en un finalizador, porque no hay garantía de que sus objetos Para finalizar, 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.

    
respondido por el Ryan Cavanaugh 25.06.2014 - 20:26
5

El propósito de este método se explica en documentación de la API de la siguiente manera:

  

se invoca siempre y cuando la máquina virtual Java haya determinado que ya no hay ningún medio por el cual se pueda acceder a este objeto por cualquier hilo que aún no haya muerto, excepto como resultado de una acción realizada por la finalización de algún otro objeto o clase que esté listo para ser finalizado ...

     

el propósito habitual de finalize ... es realizar acciones de limpieza antes de que el objeto se descarte irrevocablemente . Por ejemplo, el método de finalización para un objeto que representa una conexión de entrada / salida podría realizar transacciones de E / S explícitas para interrumpir la conexión antes de que el objeto se descarte permanentemente ...

Si además está interesado en razones por las cuales los diseñadores de idiomas han elegido que "el objeto se descarta irrevocablemente" ( basura recolectada ) la forma que está más allá del control del programador de aplicaciones ("nunca debemos confiar"), esto se ha explicado en una respuesta a la pregunta relacionada :

  

recolección automática de basura ... elimina clases enteras de errores de programación que afectan a los programadores C y C ++. Puede desarrollar el código Java con la confianza de que el sistema encontrará muchos errores rápidamente y que los principales problemas no se mantendrán inactivos hasta después de que se haya enviado el código de producción ...

La cita anterior, a su vez, se tomó de documentación oficial sobre los objetivos de diseño de Java , que Se puede considerar una referencia autorizada que explica por qué los diseñadores de lenguajes Java decidieron de esta manera.

Para una discusión más detallada y en términos de lenguaje sobre esta preferencia, consulte sección OOSC 9.6 Gestión automática de memoria (en realidad, no solo esta sección, sino todo el capítulo 9 es muy útil si está interesado en cosas como esa). Esta sección se abre con una declaración inequívoca:

  

Un buen entorno O-O debería ofrecer un mecanismo automático de gestión de memoria   que detectará y reclamará objetos inalcanzables, lo que permitirá a los desarrolladores de aplicaciones   concentrarse en su trabajo: desarrollo de aplicaciones.

     

La discusión anterior debería ser suficiente para mostrar cuán importante es tener tal   facilidad disponible En palabras de Michael Schweitzer y Lambert Strether:

     
    

Un programa orientado a objetos sin gestión automática de memoria es     aproximadamente lo mismo que una olla a presión sin válvula de seguridad: tarde o temprano     ¡La cosa está segura de explotar!

  
    
respondido por el gnat 25.06.2014 - 19:18
4

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 asegurar la limpieza (como referencias fantasma y prueba-con-recursos) no existía todavía. En retrospectiva, Java probablemente sería mejor si el esfuerzo invertido en implementar su instalación "finalizada" se hubiera invertido en otros medios de limpieza, pero eso no estuvo claro durante el tiempo en que Java se estaba desarrollando inicialmente.

    
respondido por el supercat 02.07.2014 - 18:26
3

CAVEAT: Puede que esté desactualizado, pero este es mi entendimiento desde hace unos años:

En general, no hay garantía de cuándo se ejecuta un finalizador, ni siquiera de que se ejecute, aunque algunas JVM le permitirán solicitar un GC completo y una finalización antes de que el programa finalice (lo que, por supuesto, significa que programa tarda más tiempo en salir, y no es el modo de operación predeterminado).

Y se sabía que algunos GC demoran o evitan explícitamente los objetos de GC que tenían finalizadores, con la esperanza de que esto produzca un mejor rendimiento en los puntos de referencia.

Desafortunadamente, estos comportamientos están en conflicto con los motivos originales por los que se recomendaron los finalizadores, y en su lugar se recomienda el uso de métodos de apagado explícitamente llamados.

Si tiene un objeto que realmente debe 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 ves tan a menudo en el código Java moderno como lo hiciste en algunos de los primeros ejemplos.

    
respondido por el keshlam 26.06.2014 - 01:47
1

La Guía de estilo de Google Java tiene algunos consejos sobre la asunto:

  

Es extremadamente raro anular Object.finalize .

     

Sugerencia : no lo hagas. Si es absolutamente necesario, primero lea y comprenda Java efectivo Artículo 7, "Evite los finalizadores , "con mucho cuidado, y luego no lo hagas.

    
respondido por el Daniel Pryden 26.06.2014 - 06:36
1

La Especificación del lenguaje Java (Java SE 7) estados:

  

Los finalizadores brindan la oportunidad de liberar recursos que un administrador de almacenamiento automático no puede liberar automáticamente. En tales situaciones, simplemente reclamar la memoria utilizada por un objeto no garantizaría que se reclamarían los recursos que tenía.

    
respondido por el Benni 02.07.2014 - 15:17

Lea otras preguntas en las etiquetas