usar definicion codigo java garbage-collection destructor

java - codigo - jlabel definicion



¿Hay un destructor para Java? (20)

¿Hay un destructor para Java? Parece que no puedo encontrar ninguna documentación sobre esto. Si no hay, ¿cómo puedo lograr el mismo efecto?

Para que mi pregunta sea más específica, estoy escribiendo una aplicación que trata con datos y la especificación dice que debería haber un botón de "reinicio" que devuelva la aplicación a su estado original recién lanzado. Sin embargo, todos los datos deben estar ''en vivo'' a menos que la aplicación se cierre o se presione el botón de reinicio.

Siendo usualmente un programador de C / C ++, pensé que esto sería trivial de implementar. (Y, por lo tanto, planifiqué implementarlo en último lugar). Estructuré mi programa de tal manera que todos los objetos "reiniciables" estuvieran en la misma clase, de modo que pueda destruir todos los objetos "vivos" cuando se presiona un botón de reinicio.

Estaba pensando que si todo lo que hacía era solo para eliminar la referencia a los datos y esperar a que el recolector de basura los recolectara, ¿no habría una pérdida de memoria si mi usuario ingresara los datos repetidamente y presionara el botón de reinicio? También pensaba que, como Java es bastante maduro como lenguaje, debería haber una manera de evitar que esto suceda o enfrentarlo con gracia.


Aunque ha habido avances considerables en la tecnología GC de Java, aún debe tener en cuenta sus referencias. Se me ocurren numerosos casos de patrones de referencia aparentemente triviales que en realidad son nidos de ratas debajo de la capucha.

Desde su publicación, no parece que esté intentando implementar un método de restablecimiento con el fin de reutilizar objetos (¿verdad?). ¿Sus objetos tienen algún otro tipo de recursos que deben limpiarse (es decir, las corrientes que deben cerrarse, los objetos agrupados o prestados que deben devolverse)? Si lo único que le preocupa es el desajuste de memoria, entonces reconsideraría mi estructura de objetos e intentaría verificar que mis objetos son estructuras independientes que se limpiarán en el momento de GC.


Con Java 1.7 lanzado, ahora tiene la opción adicional de usar el bloque try-with-resources . Por ejemplo,

public class Closeable implements AutoCloseable { @Override public void close() { System.out.println("closing..."); } public static void main(String[] args) { try (Closeable c = new Closeable()) { System.out.println("trying..."); throw new Exception("throwing..."); } catch (Exception e) { System.out.println("catching..."); } finally { System.out.println("finalizing..."); } } }

Si ejecuta esta clase, c.close() se ejecutará cuando se deje el bloque try , y antes de que se ejecuten los bloques catch y finally . A diferencia de en el caso del método finalize() , se garantiza que se ejecute close() . Sin embargo, no hay necesidad de ejecutarlo explícitamente en la cláusula finally .


Debe evitarse el uso de métodos finalize () . No son un mecanismo confiable para la limpieza de recursos y es posible causar problemas en el recolector de basura al abusar de ellos.

Si necesita una llamada de desasignación en su objeto, digamos, para liberar recursos, use una llamada de método explícito. Esta convención se puede ver en las API existentes (por ejemplo, Widget.dispose() , Graphics.dispose() , Widget.dispose() ) y generalmente se llama a través de try / finally.

Resource r = new Resource(); try { //work } finally { r.dispose(); }

Los intentos de usar un objeto desechado deben lanzar una excepción de tiempo de ejecución (consulte la excepción IllegalStateException ).

EDITAR:

Estaba pensando, si todo lo que hice fuera solo para eliminar la referencia a los datos y esperar a que el recolector de basura los recolectara, ¿no habría una pérdida de memoria si mi usuario ingresó los datos repetidamente y presionó el botón de reinicio?

En general, todo lo que necesita hacer es desreferenciar los objetos, al menos, esta es la forma en que se supone que debe funcionar. Si está preocupado por la recolección de basura, consulte el Ajuste de recolección de basura de máquina virtual de Java SE 6 [tm] (o el documento equivalente para su versión de JVM).


Debido a que Java es un lenguaje de recolección de basura, no puede predecir cuándo (o incluso si) se destruirá un objeto. Por lo tanto, no hay un equivalente directo de un destructor.

Existe un método heredado llamado finalize , pero esto se llama completamente a discreción del recolector de basura. Por lo tanto, para las clases que necesitan una ordenación explícita, la convención es definir un método de cierre y usar la finalización solo para verificar la validez (es decir, si no se ha llamado a cerrar, hágalo ahora y registre un error).

Hubo una pregunta que generó una discusión profunda sobre la finalización recientemente, por lo que debería proporcionar más profundidad si es necesario ...


El equivalente más cercano a un destructor en Java es el método finalize() . La gran diferencia con un destructor tradicional es que no puedes estar seguro de cuándo se llamará, ya que eso es responsabilidad del recolector de basura. Recomiendo encarecidamente leer detenidamente esto antes de usarlo, ya que sus patrones RAIA típicos para los manejadores de archivos, etc., no funcionarán de manera confiable con finalize ().


En primer lugar, tenga en cuenta que dado que Java se recolecta en la basura, es raro que tenga que hacer algo con respecto a la destrucción de objetos. En primer lugar porque normalmente no tiene recursos gestionados para liberar, y en segundo lugar porque no puede predecir cuándo sucederá o si ocurrirá, por lo que no es apropiado que ocurran cosas "tan pronto como nadie esté usando mi objeto. ".

Puede recibir una notificación después de que un objeto haya sido destruido usando java.lang.ref.PhantomReference (en realidad, decir que ha sido destruido puede ser ligeramente inexacto, pero si una referencia fantasma está en la cola, ya no es recuperable, lo que generalmente equivale a la misma cosa). Un uso común es:

  • Separe los recursos de su clase que deben destruirse en otro objeto auxiliar (tenga en cuenta que si todo lo que está haciendo es cerrar una conexión, que es un caso común, no necesita escribir una nueva clase: la conexión a ser cerrada sería el "objeto auxiliar" en ese caso).
  • Cuando crees tu objeto principal, crea también una referencia fantasma. Haga que esto se refiera al nuevo objeto auxiliar, o configure un mapa desde los objetos de PhantomReference a sus objetos auxiliares correspondientes.
  • Una vez que se recopila el objeto principal, se coloca la PhantomReference (o, más bien, se puede poner en cola), como los finalizadores, no hay garantía de que alguna vez lo sea, por ejemplo, si la VM sale, entonces no esperará). Asegúrese de que está procesando su cola (ya sea en un subproceso especial o de vez en cuando). Debido a la difícil referencia al objeto auxiliar, el objeto auxiliar aún no se ha recopilado. Así que haga la limpieza que desee en el objeto de ayudante, luego descarte la referencia fantasma y el ayudante eventualmente también será recopilado.

También está finalize (), que parece un destructor pero no se comporta como tal. Generalmente no es una buena opción.


Estoy completamente de acuerdo con otras respuestas, diciendo que no confíe en la ejecución de finalize.

Además de los bloques try-catch-finally, puede usar Runtime#addShutdownHook (introducido en Java 1.6) para realizar limpiezas finales en su programa.

Eso no es lo mismo que lo son los destructores , pero uno puede implementar un gancho de cierre con objetos de escucha registrados en los que se pueden invocar métodos de limpieza (cerrar las conexiones persistentes de la base de datos, eliminar bloqueos de archivos, etc.), cosas que normalmente se harían en destructores Nuevamente, esto no reemplaza a los constructores, pero en algunos casos, puede acercarse a la funcionalidad deseada con esto.

La ventaja de esto es que el comportamiento de deconstrucción se ha acoplado libremente con el resto de su programa.


Estoy de acuerdo con la mayoría de las respuestas.

No debes depender completamente de finalize o ShutdownHook

finalize

  1. JVM no garantiza cuándo se invocará este método finalize() .

  2. finalize() es llamado una sola vez por el subproceso GC si el objeto se revive a sí mismo a partir del método de finalización que el de finalización, no se volverá a llamar.

  3. En su aplicación, puede tener algunos objetos vivos, en los que nunca se invoca la recolección de basura.

  4. Cualquier excepción es lanzada por el método de finalización es ignorada por el hilo GC

  5. System.runFinalization(true) y Runtime.getRuntime().runFinalization(true) aumentan la probabilidad de invocar el método finalize() , pero ahora estos dos métodos han quedado en desuso. Estos métodos son muy peligrosos debido a la falta de seguridad de subprocesos y la posible creación de interbloqueo.

shutdownHooks

public void addShutdownHook(Thread hook)

Registra un nuevo gancho de apagado de máquina virtual.

La máquina virtual de Java se apaga en respuesta a dos tipos de eventos:

  1. El programa sale normalmente, cuando sale el último hilo no daemon o cuando se invoca el método exit (equivalentemente, System.exit), o
  2. La máquina virtual se termina en respuesta a una interrupción del usuario, como escribir ^ C, o un evento de todo el sistema, como el cierre de sesión del usuario o el cierre del sistema.
  3. Un gancho de apagado es simplemente un hilo inicializado pero no iniciado. Cuando la máquina virtual comience su secuencia de apagado, iniciará todos los enlaces de apagado registrados en un orden no especificado y los dejará funcionar simultáneamente. Cuando todos los ganchos hayan finalizado, se ejecutarán todos los finalizadores no invocados si se ha habilitado la finalización en la salida.
  4. Finalmente, la máquina virtual se detendrá. Tenga en cuenta que los subprocesos del daemon continuarán ejecutándose durante la secuencia de cierre, al igual que los subprocesos no daemon si el cierre se inició invocando el método de salida.
  5. Los ganchos de cierre también deben terminar su trabajo rápidamente. Cuando un programa invoca exit, la expectativa es que la máquina virtual se apague y salga rápidamente.

    Pero incluso la documentación de Oracle citó que

En raras ocasiones, la máquina virtual puede abortar, es decir, dejar de funcionar sin apagarse limpiamente

Esto ocurre cuando la máquina virtual se termina externamente, por ejemplo con la señal SIGKILL en Unix o la llamada TerminateProcess en Microsoft Windows. La máquina virtual también puede abortar si un método nativo falla, por ejemplo, al corromper las estructuras de datos internas o al intentar acceder a una memoria inexistente. Si la máquina virtual se interrumpe, no se puede garantizar si se ejecutarán o no los enganches de apagado.

Conclusión : use los bloques try{} catch{} finally{} adecuadamente y libere los recursos críticos en el bloque finally(} . Durante la liberación de los recursos en el bloque finally{} , capture Exception y Throwable .


Hay una anotación de @Cleanup en Lombok que se asemeja más a los destructores de C ++:

@Cleanup ResourceClass resource = new ResourceClass();

Al procesarlo (en el momento de la compilación), Lombok inserta el bloque try-finally apropiado para que se invoque resource.close() , cuando la ejecución deja el alcance de la variable. También puede especificar explícitamente otro método para liberar el recurso, por ejemplo, resource.dispose() :

@Cleanup("dispose") ResourceClass resource = new ResourceClass();


La función finalize() es el destructor.

Sin embargo, no debe usarse normalmente porque se invoca después del GC y no se puede saber cuándo ocurrirá (si es que ocurre).

Además, se necesita más de un GC para desasignar objetos que tienen finalize() .

Debe intentar limpiar los lugares lógicos en su código usando las declaraciones try{...} finally{...} !


Lo siento si esto se aleja del tema principal, pero la documentación de java.util.Timer (SE6) dice:

"Después de que la última referencia en vivo a un objeto del temporizador desaparece y todas las tareas pendientes se han completado, el hilo de ejecución de la tarea del temporizador termina con gracia (y queda sujeto a la recolección de basura). Sin embargo, esto puede tomar un tiempo arbitrario. Por defecto, el el subproceso de ejecución de la tarea no se ejecuta como un subproceso de demonio, por lo que es capaz de evitar que una aplicación finalice. Si el llamante desea terminar el subproceso de ejecución de la tarea del temporizador rápidamente, el invocador debe invocar el método de cancelación del temporizador ... "

Me gustaría cancelar cuando la clase que posee el temporizador pierda su última referencia (o immeditalesky antes). Aquí un destructor confiable podría hacer eso por mí. Los comentarios anteriores indican que finalmente es una mala elección, pero ¿existe una solución elegante? Ese negocio de "... capaz de evitar que una aplicación termine ..." no es atractivo.




No, no hay destructores aquí. La razón es que todos los objetos Java se asignan en montón y se recolectan basura. Sin la desasignación explícita (es decir, el operador de eliminación de C ++) no hay una forma sensata de implementar destructores reales.

Java admite los finalizadores, pero están diseñados para usarse solo como salvaguarda de los objetos que tienen un identificador para recursos nativos como sockets, identificadores de archivo, identificadores de ventana, etc. Cuando el recolector de basura recopila un objeto sin un finalizador, simplemente marca la memoria. Región tan libre y eso es todo. Cuando el objeto tiene un finalizador, primero se copia en una ubicación temporal (recuerde, estamos recolectando basura aquí), luego se pone en cola en una cola de espera para ser finalizado y luego un subproceso del finalizador sondea la cola con muy baja prioridad y ejecuta el finalizador.

Cuando se cierra la aplicación, la JVM se detiene sin esperar a que se finalicen los objetos pendientes, por lo que prácticamente no hay garantías de que sus finalizadores se ejecuten.


Pensando en la pregunta original ... creo que podemos concluir a partir de todas las otras respuestas aprendidas, y también del Java 7, "Evitar finalizadores", de Bloch, que busca la solución a una pregunta legítima de una manera que Es inapropiado para el lenguaje Java ...:

... no sería una solución bastante obvia para hacer lo que realmente quiere el OP para mantener todos los objetos que necesitan restablecerse en una especie de "parque infantil", a la que todos los demás objetos no reiniciables tienen referencias solo a través de algún tipo de objeto de acceso ...

Y luego, cuando necesita "reiniciar", desconecta el parque existente y crea uno nuevo: toda la red de objetos en el parque se coloca a la deriva, nunca para volver, y un día para ser recogido por el GC.

Si alguno de estos objetos se puede Closeable (o no, pero tiene un método close ), puede ponerlos en una Bag en el parque cuando se crean (y posiblemente se abren), y el último acto del elemento de acceso antes de cortar el parque sería ¿ Closeables pasando por todos los Closeables cerrándolos ...?

El código probablemente se vería así:

accessor.getPlaypen().closeCloseables(); accessor.setPlaypen( new Playpen() );

closeCloseables probablemente sea un método de bloqueo, que probablemente incluya un latch (por ejemplo, CountdownLatch ), para tratar (y esperar, según corresponda) cualquier Runnables / Callables en cualquier subproceso específico del Playpen que se Callables según sea apropiado, en particular en el subproceso JavaFX .


Quizás pueda usar un bloque try ... finalmente para finalizar el objeto en el flujo de control en el que está usando el objeto. Por supuesto que no sucede automáticamente, pero tampoco la destrucción en C ++. A menudo se ve el cierre de recursos en el bloque finalmente.


Si está escribiendo un applet de Java, puede anular el método "destroy ()" del applet. Es...

* Called by the browser or applet viewer to inform * this applet that it is being reclaimed and that it should destroy * any resources that it has allocated. The stop() method * will always be called before destroy().

Obviamente no es lo que quieres, pero podría ser lo que otras personas están buscando.


Si solo te preocupa la memoria, no lo hagas. Solo confía en el CG que hace un trabajo decente. De hecho, vi que era tan eficiente que podría ser mejor para el rendimiento crear montones de objetos pequeños que utilizar matrices grandes en algunos casos.


Si usa Java 7, eche un vistazo a la declaración try-with-resources . Por ejemplo:

try (BufferedReader br = new BufferedReader(new FileReader(path))) { System.out.println(br.readLine()); } catch (Exception e) { ... } finally { ... }

Aquí el recurso que ya no es necesario se libera en el método BufferedReader.close() . Puede crear su propia clase que implemente AutoCloseable y usarla de una manera similar.

Esta declaración es más limitada que la finalize en términos de estructuración de código, pero al mismo tiempo hace que el código sea más fácil de entender y mantener. Además, no hay garantía de que se llame a un método de finalize durante el tiempo de vida de la aplicación.


Solía ​​tratar principalmente con C ++ y eso es lo que me llevó también a la búsqueda de un destructor. Estoy usando mucho Java ahora. Lo que hice, y puede que no sea el mejor de los casos, pero implementé mi propio destructor al restablecer todos los valores a 0 o no por defecto a través de una función.

Ejemplo:

public myDestructor() { variableA = 0; //INT variableB = 0.0; //DOUBLE & FLOAT variableC = "NO NAME ENTERED"; //TEXT & STRING variableD = false; //BOOL }

Idealmente, esto no funcionará para todas las situaciones, pero donde hay variables globales funcionará siempre y cuando no tengas un montón de ellas.

Sé que no soy el mejor programador de Java, pero parece estar funcionando para mí.