leaks leak code avoid java memory-leaks finalizer

code - memory leak en java



Solución de problemas de una fuga de memoria java: ¿finalización? (5)

Ambas citas dicen:

Una excepción hará que la finalización de este objeto sea detenida / finalizada.

Ambas citas también dicen:

La excepción no detectada es ignorada (es decir, no registrada o manejada por la VM de ninguna manera)

Entonces eso responde la primera mitad de tu pregunta. Sin embargo, no sé lo suficiente sobre los Finalizer como para aconsejarte sobre cómo rastrear tu fuga de memoria.

EDIT: encontré esta página que podría ser de utilidad. Tiene consejos tales como establecer campos para anular manualmente en los finalizadores para permitir que el GC los recupere.

EDIT2: Algunos enlaces y citas más interesantes:

De Anatomy of a Java Finalizer

Los hilos de los finalizadores no tienen las prioridades máximas en los sistemas. Si un subproceso de "Finalizador" no puede mantener el ritmo al que los subprocesos de mayor prioridad hacen que los objetos finalizables se pongan en cola, la cola del finalizador seguirá creciendo y hará que el montón de Java se llene. Finalmente, el montón de Java se agotará y se lanzará un java.lang.OutOfMemoryError.

y también

no se garantiza que los objetos que tengan un método finalize () sean basura recolectada.

EDIT3: Al leer más sobre el enlace Anatomy, parece que lanzar excepciones en el thread de Finalizer realmente lo ralentiza, casi tanto como llamar a Thread.yield (). Parece que tiene razón en que el hilo de Finalizer eventualmente marcará el objeto como susceptible de ser sometido a GC incluso si se lanza una excepción. Sin embargo, dado que la desaceleración es significativa, es posible que en su caso el hilo del Finalizador no se mantenga al ritmo de la tasa de creación de objeto y caída del alcance.

Tengo una aplicación que funciona mal que parece tener fugas. Después de una breve investigación con el generador de perfiles, la mayoría de las memorias (80%) son retenidas por las instancias de java.lang.ref.Finalizer . Sospecho que los finalizadores no se ejecutan.

Una causa común de esto parece ser excepciones lanzadas desde el finalizador. Sin embargo, el javadoc para el método finalize de la clase Object (ver aquí por ejemplo) parece contradecirse a sí mismo: declara

Si el método finalize arroja una excepción no detectada, la excepción se ignora y la finalización de ese objeto finaliza.

pero luego, también dice que

Cualquier excepción lanzada por el método de finalización hace que se detenga la finalización de este objeto, pero de lo contrario se ignora.

¿Qué debería creer (es decir, ¿la finalización se ha detenido o no?), Y ¿tiene algún consejo sobre cómo investigar tales fugas aparentes?

Gracias


El artículo 7 de la segunda edición de Effective Java es: " Evite los finalizadores ". Te recomiendo que lo leas. Aquí hay un extracto que puede ayudarlo:

"Los métodos de terminación explícitos se usan generalmente en combinación con la construcción try-finally para asegurar la terminación"


Mi primer paso sería establecer si esta es una pérdida de memoria genuina o no.

Todos los puntos planteados en las respuestas anteriores se relacionan con la velocidad a la que se recogen los objetos, no con la cuestión de si los objetos se recolectaron o no. Solo el último es una pérdida de memoria genuina.

Tuvimos una situación similar en mi proyecto y ejecuté la aplicación en modo "cámara lenta" para ver si teníamos una fuga real. Pudimos hacer esto ralentizando el flujo de datos de entrada.

Si el problema desaparece cuando se ejecuta en modo "cámara lenta", entonces el problema probablemente sea uno de los sugeridos en las respuestas anteriores, es decir, el hilo del Finalizador no puede procesar la cola del finalizador lo suficientemente rápido.

Si ese es el problema, parece que es necesario realizar una refactorización no trivial como se describe en la página Bringer128 vinculada, por ejemplo

Ahora veamos cómo escribir clases que requieren limpieza post mortem para que sus usuarios no encuentren los problemas descritos anteriormente. La mejor manera de hacerlo es dividir dichas clases en dos: una para contener los datos que necesitan limpieza post mortem, la otra para contener todo lo demás, y definir un finalizador solo en la primera



una vez vi un problema similar, es decir, el hilo del finalizador no puede alcanzar la velocidad de generación de objetos finalizables.

mi solución es hacer un control de ciclo cerrado, usando MemoryMXBean .getObjectPendingFinalizationCount (), un control de PD (proporcional y diferencial) para controlar la velocidad en la que generamos los objetos finalizables, ya que tenemos una sola entrada para crearlo, solo dormimos número de segundos con el resultado de pd algo. funciona bien, aunque necesita ajustar el parámetro para pd algo.

Espero eso ayude.