Cuando el programa crea entidades de tipo de referencia, como objetos, matrices, etc., el sistema asignará un pedazo de memoria para el objeto en la memoria del montón, y el objeto se almacena en este pedazo de memoria. Cuando este pedazo de memoria ya no se hace referencia por ninguna variable de referencia, el trozo de memoria se convierte en basura, esperando que el mecanismo de recolección de basura sea reciclado. El mecanismo de recolección de basura tiene tres características:
El mecanismo de recolección de basura solo es responsable de reciclar objetos en la memoria del montón, y no reciclará ningún recurso físico (como conexiones de bases de datos, recursos de archivo abiertos, etc.), ni reciclará la memoria asignada al objeto de una manera distinta de la forma de crear un objeto (como la memoria aplicada por el malocleto de llamadas en el método local))
El programa no puede controlar con precisión el funcionamiento de la recolección de basura, por lo que solo se puede recomendar a la recolección de basura. Hay dos métodos recomendados: system.gc () y runtime.getRuntime (). Gc ()
Antes de la recolección de basura, su método Finalize () siempre se llamará primero, pero es lo mismo que el tiempo de recolección de basura, y el método Finalize () tampoco está seguro.
Con respecto a las tres características anteriores, hay tres problemas:
1. El trabajo de limpieza debe hacerse manualmente para liberar la memoria y otros recursos físicos asignados de una manera distinta de la forma de crear objetos. Y tenga cuidado de eliminar las referencias de objetos vencidos, de lo contrario, OOM puede ser causado.
La limpieza manual generalmente usa una estructura de código como Try ... Finalmente ...
Los ejemplos son los siguientes:
import java.io.fileInputStream; import java.io.filenotfoundException; import java.io.ioException; public class ManualClear {public static void main (string [] args) {fileInputStream fileInputStream = null; Pruebe {fileInputStream = new FileInputStream ("./ src/manualclear.java"); } Catch (FileNotFoundException e) {System.out.println (e.getMessage ()); E.PrintStackTrace (); devolver; } try {byte [] bbuf = new byte [1024]; int hasRead = 0; Pruebe {while ((haRead = fileInputStream.read (bbuf))> 0) {System.out.println (new String (BBUF, 0, Hasread)); }} catch (ioException e) {E.PrintStackTrace (); }} finalmente {try {fileInputStream.close (); } catch (ioException e) {E.PrintStackTrace (); }}}}Por lo general, hay tres casos de OOM comunes causados por referencia a objetos caducados. Estos tres casos generalmente no son fáciles de detectar, y no habrá problemas en un corto período de tiempo. Sin embargo, después de mucho tiempo, el número de objetos filtrados eventualmente hará que el programa se bloquee.
Cuando la clase administra la memoria por sí misma, debe tener cuidado con las filtraciones de memoria de la siguiente manera:
import java.util.arrays; import java.util.emptystackexception; class stack {private object [] elements; tamaño privado int; Private static final int default_inital_capacity = 16; public stack () {Elements = new Object [default_inital_capacity]; } public void push (objeto e) {EnsureCapacity (); elementos [tamaño ++] = e; } Public Object Pop () {if (size == 0) {Throw New VacchoStackException (); } Elementos de retorno [-tamaño]; } private void setureCapacity () {if (elements.length == size) {Elements = arrays.copyOf (Elements, 2 * size + 1); }}} public class StackDemo {public static void main (string [] args) {stack stack = new stack (); para (int i = 0; i <10000; i ++) {stack.push (nuevo objeto ()); } para (int i = 0; i <10000; i ++) {stack.pop (); }}}La razón para las filtraciones de memoria es que incluso si otros objetos en la pila ya no se hacen referencia, la matriz de elementos [] en la clase de pila todavía contiene referencias a estos objetos, lo que resulta en que los objetos no sean reciclados por la recolección de basura. Por lo tanto, cuando la clase necesita administrar la memoria por sí misma, tenga cuidado con si estas referencias caducadas mantenidas por internamente se desaman en el tiempo. En este ejemplo, solo después de que se lance la pila, se mostrará el mostrado.
elementos [tamaño] = nulo;
El caché debe tener cuidado con las filtraciones de memoria. Esta situación suele ser el caso de que una vez que el objeto se coloca en el caché, es probable que sea fácil de olvidar si no se usa durante mucho tiempo. Por lo general, Wakehashmap se puede usar para representar el caché. Después de que los elementos en el caché caducan, se pueden eliminar automáticamente. O puede ser ejecutado periódicamente por un hilo de fondo para borrar los elementos caducados en el búfer.
El registro de oyentes o devoluciones de llamada se muestra mejor para no registrarse.
2. No llame a finalizar () manualmente, se llama al recolector de basura
3. Evite usar el método Finalize () a menos que se use como juzgar la condición final para descubrir que el objeto no se ha limpiado correctamente; Se utiliza como una red de seguridad para limpiar los recursos del sistema cuando se limpia manualmente las llamadas olvidadas. La limpieza tardía no debe limpiarse. Si registra la información sobre el recurso de limpieza olvidado al mismo tiempo, también es conveniente que los errores se descubran más adelante y modifique el código de limpieza olvidado a tiempo; Libere los recursos del sistema no muy críticos obtenidos por el método local en el objeto.
Dado que el método Finalize () no está garantizado con precisión, es mejor no liberar recursos clave, pero puede usarse en los tres casos mencionados anteriormente. El primer caso es el siguiente:
Libro de clases {boolean checkout = false; Libro público (pago booleano) {this.eckeckout = checkout; } public void checkin () {checkout = false; } @Override Protected void finalize () lanza lanzable {if (checkout) {system.out.println ("Error: check out"); }}} clase pública finalizeCheckObjectuse {public static void main (string [] args) {nuevo libro (true); System.gc (); }}Resultados de la ejecución:
Error: consulte
El objeto del libro en el ejemplo debe estar en el estado de checkin antes de ser lanzado, de lo contrario no se puede lanzar. La implementación en finalización puede ayudar a descubrir objetos ilegales en el tiempo, o más directamente, usar una variable de referencia para referirse directamente a ella en Finalize, para que pueda volver a ingresar el estado de accesible y luego procesarlo nuevamente.
Otro punto a tener en cuenta es que si la subclase anula el método finalizar de la clase principal, pero olvida llamar manualmente a Super. Finalizar o finalizar el proceso de la subclase tiene una excepción, lo que resulta en una super. Finalizar no ser ejecutado, entonces el método final de la clase principal nunca se llamará.
como sigue:
class Parent {@Override protegido void finalize () lanza showable {system.out.println (getClass (). getName () + "Finalize Start"); }} El hijo de clases extiende a los padres {@Override protegido void finalize () lanza lando {system.out.println (getClass (). getName () + "Finalize Start"); }} clase pública SuperFinalizelostSt {public static void main (string [] args) {new son (); System.gc (); }}Resultados de ejecución:
Hijo Finalize Start
o
class Parent {@Override protegido void finalize () lanza showable {system.out.println (getClass (). getName () + "Finalize Start"); }} El hijo de clases extiende a los padres {@Override protegido void finalize () lanza lando {system.out.println (getClass (). getName () + "Finalize Start"); int i = 5/0; super.Finalize (); }} clase pública SuperFinalizelostSt {public static void main (string [] args) {new son (); System.gc (); }}Resultados de la ejecución:
Hijo Finalize Start
Para el segundo caso, puede usar la estructura Prueba ... Finalmente ... para resolverlo, pero para el primer caso, es mejor usar un método llamado Guardian del método final. El ejemplo es el siguiente
clase parent2 {objeto final privado finalGuardian = new Object () {Protected void finalize () lanza lando {system.out.println ("Ejecutar la lógica en el método de terminación de la clase principal aquí"); }; };} class SON2 extiende Parent2 {@Override protegido void finalize () lanza lando {system.out.println (getClass (). getName () + "finalizar inicio"); int i = 5/0; super.Finalize (); }} clase pública FinalizeGuardian {public static void main (string [] args) {new son2 (); System.gc (); }}Resultados de la ejecución:
Ejecutar la lógica en el método de terminación de clase principal aquí
Son2 Finalize Start
Esto asegura que se ejecuten las operaciones requeridas en el método final de la clase principal.
Lo anterior se trata de este artículo, espero que sea útil para el aprendizaje de todos.