2011-02-13 11 views
26

Me hacen esta pregunta muchas veces. ¿Cuál es una buena manera de responder?Puede haber pérdida de memoria en Java

EDIT: Gracias a todos por todas las respuestas.

+1

recurso muy detallado aquí: http://www.ibm.com/developerworks/library/j-leaks/ –

+0

Esta pregunta se ha hecho tantas veces como usted sugiere, y de hecho tiene muchas respuestas en este foro ya . –

+1

Buena pregunta. Aprendí muchas cosas de las respuestas. – fastcodejava

Respuesta

19

Can there be memory leak in Java?

La respuesta es que Depende del tipo de pérdida de memoria de la que estés hablando t.

Las pérdidas de memoria de C/C++ clásicas se producen cuando una aplicación omite free o dispose un objeto cuando han terminado con él, y tiene fugas. Las referencias cíclicas son un sub-caso de esto donde la aplicación tiene dificultades para saber cuándo free/dispose, y deja de hacerlo como resultado. Los problemas relacionados se producen cuando la aplicación utiliza un objeto después de que se ha liberado o intenta liberarlo dos veces. (Se podría llamar los últimos problemas de pérdidas de memoria, o sólo errores. De cualquier manera ...)

Java y lenguajes su mayoría no sufren de estos problemas otra (totalmente) gestionado debido a que el GC se encarga de liberar objetos que ya no son alcanzables. (Ciertamente, el puntero colgante y los problemas de doble liberación no existen, y los ciclos no son problemáticos, como lo son para los "indicadores inteligentes" de C/C++ y otros esquemas de recuento de referencias).

Pero en algunos casos, GC en Java pierda objetos que (desde la perspectiva del programador) deberían ser recolectados. Esto sucede cuando el GC no puede descubrir que un objeto no puede ser alcanzado:

  • La lógica/estado del programa puede ser tal que las rutas de ejecución que usarían alguna variable no pueden ocurrir. El desarrollador puede ver esto como obvio, pero el GC no puede estar seguro, y se equivoca por el lado de la precaución (como se requiere).
  • El programador podría estar equivocado al respecto, y el GC evita lo que de lo contrario podría dar como resultado una referencia indefinida.

(Tenga en cuenta que las causas de las pérdidas de memoria en Java pueden ser simples o muy sutiles;. Véase la respuesta de @ jonathan.cone para algunas sutiles El último que potencialmente implica recursos externos que no debería confía en el GC para tratar de todos modos.)

De cualquier forma, puede tener una situación en la que los objetos no deseados no puedan ser recolectados, y evitar la acumulación de memoria ... una pérdida de memoria.

Luego está el problema de que una aplicación o biblioteca Java puede asignar objetos fuera de pila a través de código nativo que necesita ser administrado manualmente. Si la aplicación/biblioteca tiene errores o se usa incorrectamente, puede obtener una pérdida de memoria nativa. (Por ejemplo: Android Bitmap memory leak ... señalando que se solucione este problema en versiones posteriores de Android.)


1 - Estoy aludiendo a un par de cosas. Algunos idiomas administrados le permiten escribir código no administrado en el que puede crear fugas clásicas de almacenamiento. Algunos otros lenguajes administrados (o más concretamente implementaciones de lenguaje) usan recuento de referencias en lugar de recolección de basura adecuada.Un administrador de almacenamiento basado en el recuento de referencias necesita algo (es decir, la aplicación) para interrumpir los ciclos ... de lo contrario, se producirán fugas de almacenamiento.

+0

+1 para los detalles. – fastcodejava

3

sí, si no quita la referencia a los objetos, nunca se recolectarán basura y aumentará el uso de la memoria. sin embargo, debido a la forma en que está diseñado java, esto es difícil de lograr, mientras que en otros idiomas esto a veces es difícil de lograr.

editar: leer el enlace de Amokrane. es bueno.

+0

Si no está haciendo referencia al objeto, puede ser GC'd. Si estás (y no en un circuito cerrado), entonces no es una "fuga". Ipso, facto. –

+1

@ T.J. Crowder: Esa es una muy ... estricta interpretación de "fuga". Y no es muy útil, en eso. Supongamos que alguna clase mantiene un caché interno de varios objetos, pero sigue volviendo a agregar nuevas instancias a ese caché en lugar de volver a utilizarlas. El uso de la memoria sigue aumentando y el montón está lleno de objetos que nunca volverán a usarse, y eso a mí me parece una "fuga de memoria". –

+0

@Anon: en su mayor parte era frívola. Pero su punto es realmente una buena * respuesta *, sugiero agregarlo como uno solo. –

2

La respuesta corta:

A competent JVM has no memory leaks, but more memory can be used than is needed, because not all unused objects have been garbage collected, yet. Also, Java apps themselves can hold references to objects they no longer need and this can result in a memory leak.

Una respuesta aún más corto:

Java is a language and can't have memory leaks, only Java Virtual Machines can.

+1

No creo que esto sea útil. El hecho es que las ** aplicaciones ** de Java pueden, y a menudo tienen, pérdidas de memoria. –

+0

@Stephen, gracias, he actualizado mi respuesta para que sea menos ambigua. –

+0

¿Cómo pueden las JVM tener pérdidas de memoria cuando no son las que tienen la memoria? – Pacerier

2

Sí, es posible.

En Java efectivo hay un ejemplo que involucra una pila implementada usando matrices. Si sus operaciones pop simplemente disminuyen el valor del índice, es posible tener una pérdida de memoria. ¿Por qué? Debido a que su matriz todavía tiene una referencia al valor reventado y todavía tiene una referencia al objeto de la pila. Entonces, lo correcto para esta implementación de pila sería borrar la referencia al valor reventado utilizando una asignación nula explícita en el índice de matriz reventado.

4

Sí, en el sentido de que su aplicación Java puede acumular memoria a lo largo del tiempo que el recolector de basura no puede liberar.

Al mantener las referencias a los objetos no deseados/no deseados, nunca se saldrán del alcance y su memoria no volverá a reclamarse.

8

Sí. Las fugas de memoria aún pueden ocurrir incluso cuando tiene un GC. Por ejemplo, puede conservar recursos como los conjuntos de resultados de la base de datos que debe cerrar manualmente.

0

Una respuesta simple es: JVM se encargará de toda tu inicialización de POJO [objetos antiguos de java] siempre que no estés trabajando con JNI. Con JNI, si ha realizado alguna asignación de memoria con el código nativo, debe ocuparse de esa memoria usted mismo.

10

Bueno, teniendo en cuenta que java utiliza un recolector de basura para recoger objetos no utilizados, no puede tener un puntero colgando. Sin embargo, puede mantener un objeto en el alcance durante más tiempo de lo necesario, lo que podría considerarse una pérdida de memoria. Más sobre esto aquí: http://web.archive.org/web/20120722095536/http://www.ibm.com:80/developerworks/rational/library/05/0816_GuptaPalanki/

¿Estás tomando una prueba sobre esto o algo así? Porque eso es al menos un A + justo allí.

+0

Respuesta agradable y simple. – vz0

+1

su enlace no funciona y está roto –

5

La respuesta es un rotundo sí , pero esto es generalmente un resultado del modelo de programación más que una indicación de algún defecto en la JVM. Esto es común cuando los marcos tienen ciclos de vida diferentes de eso que una JVM en ejecución.Algunos ejemplos son:

  1. Reloading a context
  2. Failing to dereference observers (listeners)
  3. Forgetting to clean up resources after you're finished using them *

* - Los mil millones de dólares de consultoría se han hecho para resolver el último

0

Sí. Una pérdida de memoria es una memoria no utilizada que la aplicación no ha liberado al administrador de memoria.

que he visto muchas veces Java almacena código wich elementos en una estructura de datos, pero los artículos nunca se retiran de allí, llenando la memoria hasta un OutOfMemoryError:

void f() { 
    List<Integer> w = new ArrayList<Integer>(); 
    while (true) { 
     w.add(new Integer(42)); 
    } 
} 

Aunque este ejemplo es demasiado obvio, Java los errores de memoria tienden a ser más sutiles. Por ejemplo, usando Dependency Injection almacenando un objeto enorme en un component with SESSION scope, sin soltarlo cuando el objeto ya no se usa.

En una VM de 64 bits, esto tiende a empeorar ya que el espacio de memoria de intercambio comienza a llenarse hasta que el sistema rastrea en demasiadas operaciones de IO.

+0

Esto no es una pérdida de memoria, es solo una programación deficiente. Todos estos objetos todavía se pueden referenciar para que no se "filtren" – ed209

2

El libro Effective Java da dos razones más para "pérdidas de memoria":

  • Una vez que pones referencia de objeto en caché y olvidar que está allí. La referencia permanece en el caché mucho antes de volverse irrelevante. La solución es representar el caché como WeakHashMap
  • en una API donde los clientes registran las devoluciones de llamada y no las vuelven a registrar explícitamente. La solución es almacenar solo referencias débiles para ellos.
Cuestiones relacionadas