repentina - Puede haber pérdida de memoria en Java
perdida de memoria repentina (11)
Me hacen esta pregunta muchas veces. ¿Cuál es una buena manera de responder?
EDITAR : Gracias a todos por todas las respuestas.
¿Puede haber pérdida de memoria en Java?
La respuesta es que depende del tipo de pérdida de memoria de la que está hablando.
Las fugas clásicas de la memoria C / C ++ ocurren cuando una aplicación deja de free
o dispose
un objeto cuando termina y tiene fugas. Las referencias cíclicas son un sub-caso de esto donde la aplicación tiene dificultad 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. (Podrías llamar a estos últimos problemas de pérdida de memoria, o simplemente errores. De cualquier forma ...)
Java y otros lenguajes (totalmente 1 ) gestionados en su mayoría no sufren estos problemas porque el GC se encarga de liberar objetos que ya no son alcanzables. (Ciertamente, los problemas de puntero colgante y 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 omitirá objetos que (desde la perspectiva del programador) deberían ser recolectados. Esto sucede cuando el GC no puede entender 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 puedan 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 está evitando lo que de lo contrario podría resultar en una referencia que cuelga.
(Tenga en cuenta que las causas de las pérdidas de memoria en Java pueden ser simples o bastante sutiles, vea la respuesta de @ jonathan.cone para algunas sutiles. La última potencialmente involucra recursos externos de los que no debe depender el GC para tratar de todos modos. )
De cualquier manera, puede tener una situación en la que los objetos no deseados no puedan ser recolectados como basura, y no ocupe la memoria ... una fuga de memoria.
Luego está el problema de que una aplicación o biblioteca Java puede asignar objetos fuera de pila a través de un 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: pérdida de memoria de mapa de bits de Android ... señalando que este problema está solucionado en las versiones posteriores de Android).
1 - Estoy haciendo alusión 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.
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? Porque eso es al menos un A + justo allí.
El libro Effective Java da dos razones más para "pérdidas de memoria":
- Una vez que colocas referencia de objeto en Caché y olvidas que está ahí. La referencia permanece en el caché mucho antes de volverse irrelevante. La solución es representar el caché como un 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.
La respuesta corta:
Una JVM competente no tiene pérdidas de memoria, pero se puede usar más memoria de la necesaria porque todavía no se han recogido todos los objetos no utilizados. Además, las propias aplicaciones Java pueden contener referencias a objetos que ya no necesitan y esto puede provocar una pérdida de memoria.
Una respuesta aún más corta:
Java es un lenguaje y no puede tener pérdidas de memoria, solo Java Virtual Machines puede hacerlo.
La respuesta es un sí rotundo, pero generalmente es 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:
- Recargar un contexto
- Fallar en la desreferencia de observadores (oyentes)
- Olvidarse de limpiar los recursos después de que haya terminado de usarlos *
* - Se han realizado miles de millones de dólares de consultoría para resolver el último
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 referencias a objetos no deseados / no deseados, nunca se saldrán del alcance y su memoria no será recuperada.
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.
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.
Sí. Una pérdida de memoria es una memoria no utilizada que la aplicación no ha liberado al administrador de memoria.
He visto muchas veces código Java que almacena elementos en una estructura de datos, pero los elementos nunca se eliminan de allí, llenando la memoria hasta un OutOfMemoryError:
void f() {
List<Integer> w = new ArrayList<Integer>();
while (true) {
w.add(new Integer(42));
}
}
Si bien este ejemplo es demasiado obvio, los errores de memoria de Java tienden a ser más sutiles. Por ejemplo, usando Dependency Injection almacenando un objeto enorme en un componente con el alcance de SESSION
, sin soltarlo cuando el objeto ya no se usa.
En una máquina virtual 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.
Una respuesta simple es: JVM se encargará de toda tu inicialización de POJO [simples 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.
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: lee el enlace de Amokrane. es bueno.