Cómo funciona la memoria en Java

Como he tenido que empaparme de su funcionamiento, aprovecho y pongo un post sobre conceptos básicos de la memoria en Java.

Note: This post is a bit old so the default strategy on JVM may have changed since. Although the basics are the same.

Heap y Non-Heap

Para empezar, Java divide la memoria en dos segmentos bien diferenciados:

  • Heap: Objetos del usuario, variables, ...
  • Non-Heap/Perm: Código, metadatos, ...

La que más nos interesa es la Heap, porque es la que podemos "controlar". A la memoria Non-Heap (Perm) se le puede configurar el tamaño con el comando MaxPermSize. Pero esto sólo es útil si la aplicación va a cargar o generar dinámicamente muchas clases diferentes.

Generaciones

La memoria heap se divide a su vez en dos generaciones según su tiempo de vida:

  • Young Generation
  • Old Generation

Usually the younger generation is composed of local variables and temporary objects. While the older generation usually consists of structures that are necessary during the execution: configurations, viewports,…

A su vez, la generación joven se divide en dos:

  • Eden: Aquí es donde se crean los objetos inicialmente
  • Survivor: Es como el limbo a través del cual se pasa de la generación joven a la vieja. Suele estar compuesto a su vez en dos partes.

Se puede especificar el ratio entre el espacio de la generación joven y el espacio de la generación vieja con el comando de la máquina virtual -XX: NewRatio .

El Recolector de Basura (Garbage Collector)

El Recolector de Basura ( Garbage Collector ) realiza dos tipos de tareas periódicas:

  • Minor Collection: Que revisa de forma rápida la generación joven.
  • Major Collection: Que revisa de forma exhaustiva toda la memoria, fundamentalmente la generación vieja.

The garbage collector runs at the same time as the normal program execution. Each execution involves a small pause (usually milliseconds) in all the threads that are running at that time. As memory remains more or less freed, the Garbage Collector will be limited to minor collections, to not interfere with the flow of the application.

Para tener una idea más exacta de cómo trabaja, se puede añadir la opción -verbose:gc a la máquina virtual. Este comando irá imprimiendo cada vez que se ejecute el Recolector de Basura cuanto espacio de memoria ha conseguido liberar.

Different memory strategies

Existen varias implementaciones del Recolector de Basura, siendo la más común el Serial Collector. Esta implementación, además de ser la más sencilla, utiliza sólo un procesador. Si se está usando una máquina más potente, con varios procesadores y una buena cantidad de memoria física, se puede activar el Parallel Collector , que utiliza varias CPUs a la vez. Esto mejora la forma en la que funciona el Recolector de Basura, pero también puede paralizar a ratos el flujo de ejecución normal de la aplicación.

De todas formas, para el buen funcionamiento y limpieza de la memoria, conviene tener pequeños objetos temporales de vida corta antes que objetos largos y duraderos. Los pequeños objetos temporales se quedarán en el Eden, por lo que se recolectarán mucho antes y de forma mucho más rápida.

Así mismo, tener objetos en memoria sin usar, aunque no molesten a la ejecución del programa, ralentizan la ejecución del Recolector de Basura, porque tendrá que procesarlos una y otra vez en todas sus pasadas.

Forzando la recolección de basura

En algún momento puede parecer tentador forzar una ejecución del Recolector de Basura llamando a System.gc(). Sin embargo, esto lo único que hará será forzar una major collection de forma asíncrona, rompiendo completamente toda la heurística del Recolector de Basura. Es tan desaconsejable que hasta hay una opción en la máquina virtual para desactivar estas llamadas: -XX:+DisableExplicitGC .

Para ayudar a la tarea del Recolector de Basura, existen tres tipos de referencias :

  • Weak: No impide al recolector de basura llevárselo.
  • Soft: Como el weak, pero el recolector de basura lo respeta un poco más y sólo se lo lleva si le hace falta memoria. Útil para cachés, pero puede ser engañoso.
  • Phantom: Siempre devuelve null, no accede al objeto realmente, pero puede servir servir para limpiar antes de que se lleven al objeto que lo enlaza.

Una clase que explica bastante bien el funcionamiento de este tipo referencias es  WeakHashMap: Funciona como un HashMap, pero usando referencias Weak. De esta forma, si las claves que contiene sólo están referenciadas en dicho HashMap, considera que ya no son útiles y las borra.

Referencias útiles:

Autor: María Arias de Reyna Domínguez

Redhatter, Feminist, Geoinquieta, Atheist, crazy of the pussy and Social Justice Warrior. Chaotic good.

4 opiniones en “How does Memory work on Java”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *