5

Por lo tanto, recientemente descubrí el método de finalización en Java (no estoy seguro de por qué me lo perdí antes, pero ahí está). Esto parece como podría ser la respuesta a muchos de los problemas con los que estoy trabajando, pero primero quería obtener un poco más de información.¿Cómo funciona el finalize() en Java?

en línea, me encontré con este diagrama que ilustra el proceso de recolección de basura y finalizar:

This describes the order of operations involving finalize and the JGC:

Un par de preguntas:

  1. Esto se lleva a cabo en un hilo separado, correcto?
  2. ¿Qué sucede si instancia un nuevo objeto durante la finalización? eso está permitido?
  3. ¿Qué sucede si solicito finalizar un método estático?
  4. ¿Qué sucede si establezco una nueva referencia al objeto desde el final?

supongo que debería explicar por qué estoy interesado. Trabajo mucho con LWJGL, y parece que si pudiera usar finalizar para hacer que los objetos de Java limpien automáticamente los recursos de OpenGL, entonces podría hacer algunas cosas realmente buenas en términos de una API.

+2

Esta no es una respuesta directa a su pregunta, pero sepa que finalizar no está garantizado y que es una de las muchas razones por las que no se usa mucho. (EDITAR: e incluso si lo es, se llamará debido a la presión de la memoria en la memoria administrada por Java. Eso significa que si está intentando usarlo para liberar otros recursos, entonces puede quedarse sin ellos y tener el programa se bloquea aunque la limpieza podría reclamarlos a todos, solo porque Java no sabe que ejecutar el GC reclamará (por ejemplo) identificadores de archivos). – jacobm

Respuesta

3

No creo que haya ninguna garantía sobre qué hilo se utilizará. Se pueden crear instancias de objetos nuevos y se pueden llamar a métodos estáticos. Establecer una nueva referencia a su objeto evitará que se recolecte basura, pero se llamará de nuevo al método finalizeno; no desea hacer esto.

La limpieza de los recursos es precisamente para lo que es el método finalize, por lo que debe ser bueno allí. Sin embargo, un par de advertencias:

No se garantiza el llamado del método. Si tiene recursos atados que no se liberarán automáticamente cuando su programa se detenga no dependa de finalize.

Cuando se llama al método no está garantizado. Con la memoria apretada, esto será más rápido. Con mucha memoria libre, será más tarde en todo caso. Puede que le quede bien: con mucha memoria, puede que no le preocupe liberar los recursos. (Aunque se aferran a ellos puede interferir con otro software que funciona al mismo tiempo, en cuyo caso se le estar preocupado.)

Mi solución horneadas es tener algún tipo de disponer método que hace la limpieza . Lo llamo explícitamente en algún momento si puedo, y tan pronto como pueda. Luego agrego un método de finalización que solo llama al , elimine el método. (Tenga en cuenta que el disponer método debe se comportan bien cuando cuando se le llama más de una vez! De hecho, con este tipo de programación que podría llamar disponer varias veces fuera finalize, al no estar seguro de si se hicieron las llamadas anteriores querer con éxito y sin embargo debe llamarse efectivamente tan pronto como sea posible.) Ahora, idealmente, mis recursos se liberan tan pronto como ya no los necesite.Sin embargo, si pierdo la pista del objeto con los recursos, el método finalize me rescatará cuando la memoria se agote y necesite la ayuda.

5

finalize() es invocado por Java Garbage Collector cuando detecta que no existen referencias a ese objeto en particular. finalize() es heredado por todos los objetos Java a través de la clase Object.

Por lo que yo sé, no tendría dificultades para realizar llamadas a métodos estáticos desde un método finalize() y podría establecer una nueva referencia desde finalize(); sin embargo, diría que es una práctica de programación deficiente.

No debe confiar en finalize() para la limpieza, y es mejor aclararlo sobre la marcha. Prefiero usar try, catch, finalmente para limpiar, en lugar de usar finalize(). En particular, al usar finalize() hará que la JVM se atenga a todos los demás objetos a los que hace referencia su objeto finalizable, en caso de que les haga llamadas. Esto significa que puedes retener la memoria que quizás no necesites usar. Lo que es más importante, esto también significa que puede hacer que la JVM nunca termine deshaciéndose de los objetos, ya que deben aferrarse a ellos en caso de que otro método de finalización de objetos lo necesite, p. una condición de carrera.

Además, tenga en cuenta que es muy posible que no se invoque GC. Por lo tanto, no puede realmente garantizar que finalizará() alguna vez se llamará.

Limpiar recursos a medida que haya terminado con ellos, y no confíe en finalizar() para hacerlo es mi consejo.

1

Antes que nada, recuerde que no hay garantía de que la finalización se ejecute en absoluto para todos sus objetos. Puede usarlo para liberar memoria asignada en código nativo asociado con un objeto, pero para código Java puro la mayoría de los casos de uso son solo para realizar un mecanismo de "copia de seguridad" de limpieza de recursos. Esto significa que en la mayoría de los casos debe liberar recursos manualmente y los finalizadores podrían actuar solo como un tipo de ayudante para limpiar si olvida hacerlo de la manera estándar. Sin embargo, no puede usarlos como el único o principal mecanismo de limpieza. Incluso más generalmente, no debe escribir ningún código cuya corrección dependa de los finalizadores que se ejecutan.

Anuncio 1.Por lo que yo sé, no hay garantías sobre qué hilo llama a finalize(), aunque en la práctica probablemente sea uno de los hilos de GC.

Anuncio 2. Se permite la instanciación de objetos nuevos. Sin embargo, hay una serie de dificultades con el manejo de referencias de objetos en los finalizadores. En particular, si almacena una referencia difícil al objeto que se está finalizando en algún objeto activo, puede evitar que se limpie el objeto que se va a recoger. Este tipo de resurrección de objetos puede llevar a agotar sus recursos si se sale de control. Además, tenga cuidado con las excepciones en finalize(); pueden detener la finalización, pero no hay una manera automática de que su programa las conozca. Debe envolver el código en bloques de prueba y propagar la información usted mismo. Además, el tiempo de ejecución prolongado de los finalizadores puede hacer que la cola de objetos se acumule y consuma mucha memoria. Algunos otros problemas y limitaciones notables se describen en this JavaWorld article.

Anuncio 3. No debería haber ningún problema al llamar a los métodos estáticos desde los finalizadores.

Anuncio 4. Como se menciona en el punto 2, es posible evitar que un objeto sea recolectado como basura (para resucitarlo) al colocar una referencia en otro objeto activo durante la finalización. Sin embargo, este es un comportamiento difícil y probablemente no una buena práctica.

En resumen, no puede confiar en los finalizadores para limpiar sus recursos. Debe manejarlo de forma manual y los finalizadores en su caso pueden, en el mejor de los casos, utilizarse como un mecanismo de copia de seguridad para cubrirse después de una codificación descuidada hasta cierto punto. Esto significa que, desafortunadamente, su idea de mejorar la API mediante el uso de finalizadores para limpiar los recursos de OpenGL probablemente no funcione.

Cuestiones relacionadas