2009-08-15 16 views
48

¿Qué clases de la API estándar de Java pueden causar pérdidas de memoria cuando se usan de una manera (no obviamente) incorrecta? ¿Y cómo se pueden evitar/corregir estas pérdidas de memoria?Fugas de memoria en la API estándar de Java

Ejemplo:ObjectInputStream y ObjectOutputStream mantienen referencias a todos los objetos que han visto el fin de enviar las ocurrencias subsiguientes de un mismo objeto como referencias en lugar de copias (y de ese modo tratar con referencias circulares). Esto provoca una pérdida de memoria cuando mantiene dicha corriente abierta indefinidamente (por ejemplo, cuando la usa para comunicarse a través de la red).

Solución: Reinicio de llamada() periódicamente o después de cada objeto de nivel superior.

+3

@Michael - tal vez mueva su ejemplo a una respuesta por sí mismo? –

Respuesta

46

Una de las grandes es que obtener subcadenas de cadenas Java se refiere a la cadena original.

Ejemplo: lee en un registro de 3000 caracteres y obtiene una subcadena de 12 caracteres, devolviéndola a la persona que llama (dentro de la misma JVM). Aunque no tenga una referencia directa a la cadena original, esa cadena de 12 caracteres aún usa 3000 caracteres en la memoria.

Para sistemas que reciben y luego analizan un montón de mensajes, esto puede ser un problema real.

usted tiene un par de maneras de evitar esto:

String sub = new String(str.substring(6,12)); 

o

String sub = str.substring(6,12).intern(); 

El primero es más bien definida. El segundo tiene otras implicaciones porque estás usando el espacio PermGen. Si se usa demasiado, puede agotarse a menos que le dé suficiente a su máquina virtual.

Recuerda que esto solo es relevante si tomas subcadenas pequeñas y luego tiras la cuerda original y estás haciendo esto mucho.

+1

¿Qué le parece mencionar una solución simple como crear un nuevo objeto String explícitamente? –

+0

No toparse con un hilo muy viejo pero, ¿cuál es el motivo? ¿Por qué esta línea "str = str.substring (6,12)" desperdicia un espacio de 3k caracteres, en lugar de solo 6? –

+2

@Murat: chocando un comentario anterior: porque internamente se refiere a la misma matriz de caracteres que la cadena original, solo con un desplazamiento y longitud diferentes. Si crea muchas subcadenas superpuestas, realmente ahorra memoria. –

4

Cualquier clase con el método de eliminación()?

Por ejemplo java.awt.Window#dispose:

public void disponer()

Libera todos los recursos nativos de pantalla utilizados por esta ventana, sus subcomponentes, y todos sus elementos secundarios que pertenecen. Es decir, los recursos para estos componentes se destruirán, cualquier memoria que consuman se devolverá al sistema operativo y se marcarán como no reproducibles.

8

Todo lo que registra como destinatario de un evento, p. en marcos de GUI, no se puede recolectar basura mientras esté registrado y la fuente de evento está activa.

Esto puede presentar pérdidas de memoria, si un desarrollador no tiene conocimiento de esa referencia fuerte del origen del evento al suscriptor del evento.

+0

Es una buena idea usar referencias débiles para cualquier oyente que se espera que viva más de lo que está escuchando. –

+0

Este es casi el ejemplo estándar para una pérdida de memoria, porque es obvio pero fácil de olvidar. –

5

Cada instanciación de un subproceso asigna memoria para una pila (por defecto 512k, sintonizable a través de -Xss).No se trata de una fuga como tal, pero un intento ingenuo de aplicar múltiples hilos en una aplicación resultará en un considerable consumo no obvio de memoria.

+3

En realidad, puede convertirse en una fuga absoluta si crea objetos Thread y nunca llama a start() - la memoria de la pila nunca se reclama, IIRC. –

+0

Interesante. No lo sabía –

+2

@Michael Borgwardt: No creo que sea el caso; ¿Tienes una fuente? \ [edit \]: parece que puede haber sido un error en versiones anteriores de la JVM, pero debe corregirse en Java 5. – Miles

7

Cualquier clase interna no estática que haga retener clases externas. Para que la clase interna de aspecto inocente pueda aferrarse a un enorme gráfico de objetos. Coloque la instancia en una colección estática o de toda la aplicación en algún lugar y está usando un lote de memoria que no debe usar.

3

Uso de referencias fuertes cuando las referencias débiles hubieran sido suficientes. La aplicación y las API que realizan su propia administración de recursos y estado son los culpables habituales aquí.

Luego, está el uso del patrón Observer, que podría provocar pérdidas de memoria: cuando el observador se desmarca del Asunto, la memoria no puede recuperarse a menos que el Sujeto también libere la referencia al Observador/Escuchador. Esto ya se ha señalado anteriormente, pero no muchas personas se dan cuenta de que incluso los madereros son observadores.

Además, there is the likelihood of classes, whose objects when instantiated are automatically placed into a static member. Algunas de estas clases ni siquiera tienen un método de liberación() o un método de eliminación() para que el miembro estático mantenga las referencias. Esta variedad de pérdidas de memoria finalmente produce un error OutOfMemory con un problema de espacio PermGen informado como la causa raíz, por lo que es más difícil de diagnosticar.