Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Tipos de Memoria
En Java podemos hablar de tres zonas de memoria:
prietopa)
Ventajas y Desventajas de la Gestin Dinmica
Una desventaja de la gestin de memoria en Java es que nosotros no controlamos
donde queremos asignar nuestra memoria. Asignar memoria en el HEAP es ms
costoso y tambin liberar dicha memoria, por eso, a veces es deseable almacenar
un objeto en la memoria STACK.
Entre las ventajas de la gestin dinmica es que no tenemos que preocuparnos por
asignar y desasignar memoria, puesto que es un proceso dinmico. Adems la
JVM internamente utiliza una optimizacin llamada anlisis de escape (en
ingls scape analysis) que realiza comprobaciones para saber si un objeto se utiliza
slo en un thread o un mtodo y crearlo en la memoria STACK, incrementando el
rendimiento de nuestros programas.
Garbage Collector
Como hemos mencionado anteriormente, el Garbage Collector o recolector de
basura es un proceso automtico de baja prioridad que se ejecuta dentro de la JVM.
Se encarga de limpiar aquella memoria del HEAP que ya no se utiliza y por tanto,
podra ser utilizada por otros programas. Cmo sabe la memoria que no se utiliza?
Un objeto podr ser limpiado cuando desde el STACK ninguna variable haga
referencia al mismo.
Si queremos saber cuando se ejecutar el GC deberemos utilizar el
parmetro "-verbose:gc" antes de arrancar nuestra JVM.
1
2
3
4
5
6
7
8
9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
package es.jpascu.test;
import java.util.ArrayList;
import java.util.List;
public class TestJVMMemory {
private static final long MEGABYTE = 1024L * 1024L;
public static long bytesToMegabytes(long bytes) {
return bytes / MEGABYTE;
}
public static void main(String[] args) {
List<item> list = new ArrayList<item>();
for (int i = 0; i <= 1000000; i++) {
Item item = new Item("1", "UN MURCIANO EN EL POLO",
2);
list.add(item);
}
// Obtenemos la runtime de Java
Runtime runtime = Runtime.getRuntime();
// Ejecutamos el proceso de Garbage Collector
runtime.gc();
// Calculamos la memoria mxima y la memoria
disponible
long memory = runtime.totalMemory() runtime.freeMemory();
long memoriaMax = runtime.maxMemory();
System.out.println("Memoria mxima en bytes: " +
memoriaMax);
System.out.println("Memoria mxima en MB: "
+ bytesToMegabytes(memoriaMax));
System.out.println("Memoria utilizada en bytes: " +
memory);
System.out.println("Memoria utilizada en MB: "
+ bytesToMegabytes(memory));
}
}
</item></item>
2
9
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
3
8
Para indicar el tamao mnimo que tiene la memoria HEAP utilizamos el parmetro:
Compilador JIT.
En las primeras versiones de Java, la JVM era tan slo un intrprete de cdigos de
byte de Java. Esto haca que la mayora de los programas se ejecutaran con
lentitud, ya que la JVM tena que interpretar y ejecutar un cdigo de bytes a la vez.
Por lo general, las JVMs actuales ejecutan cdigos de bytes usando una combinacin
de la interpretacin y la denominada compilacin justo a tiempo (JIT). En este
proceso, la JVM analiza los cdigos de bytes a medida que se interpretan, buscando
puntos activos: partes de los cdigos de bytes que se ejecutan con frecuencia.
Para estas partes, un compilador justo a tiempo (JIT y conocido como compilador
HotSpot de Java) traduce los cdigos de bytes al lenguaje mquina correspondiente
a la computadora. Cuando la JVM encuentra estas partes compiladas nuevamente,
se ejecuta el cdigo en lenguaje mquina, que es ms rpido. En consecuencia, los
programas en Java en realidad pasan por dos fases de compilacin: una en la cual el
cdigo fuente se traduce a cdigo de bytes (para tener portabilidad a travs de las
JVMs en distintas plataformas computacionales) y otra en la que, durante la
ejecucin, los cdigos de bytes se traducen en lenguaje mquina para la
computadora actual en la que se ejecuta el programa.
Almacena
STACK
HEAP
Variables
locales
Objetos (clases,
mtodos,
instancias)
Nunca se
Se puede
puede
manipular
directamente
redimensionar y
tiene el Garbage
Collector
Tiene acceso
al procesador,
stack pointer
no
La memoria no
necesita ser
Idem
contigua
Cada hilo tiene Comn a toda la
un stack
JVM
OutOfMemory
No tiene
Necesita ms
espacio para
tamao.
un nuevo hilo.
StackOverflow
Requiere ms
espacio del
permitido
Ejemplo:
Heap (04567= 83)
name = Susan
age = 26
city= London
height= 57
sex= female
var blue
var red
ref 0456783= (Heap reference)
var tom
ref 0498702= (Heap reference) Heap (04987= 02)
name= Paul
var diane
age= 21
city = Glasgow
height = 60
sex = male
Ejemplo grafico
Bibliografia:
http://wiki.answers.com/Q/What_is_difference_between_heap_memory_and_stack_m
emory
- http://www.sap-img.com/java/difference-between-stack-and-heap.htm
- http://www.soygeek.com/index.php/2008/02/12/almacenamiento-en-java/
- http://net.pku.edu.cn/~course/cs101/2008/resource/heapAndStack.html
2 Visin
La JVM (mquina virtual Java).
La maquina virtual de java -o JVM en sus siglas en ingls- es el anclaje fsico de nuestro
maravilloso lenguaje multiplataforma con el Sistema Operativo correspondiente y, como tal,
ocupa y utiliza memoria del sistema. Bien, esto es evidente pero, lo que es menos conocido,
es como est implementada esta gestin de memoria.
La JVM se arranca reservando, por defecto, 64MB de memoria para trabajar que va
ampliando segn necesidades. Sin embargo, estas sucesivas ampliaciones automticas
llegan a un lmite. Podemos gestionar nosotros mismos estos lmites -tanto por arriba como
por abajo- gracias a unos parmetros con los que se puede acompaar al comando de
arranque de la JVM.
Esto es IMPORTANTE si sabemos que nuestra aplicacin va a requerir una gran cantidad de
memoria para su funcionamiento y queremos evitar un OutOfMemoryError o si, por el
contrario, nuestra aplicacin compite con otras de mayor prioridad en un sistema y queremos
que utilice solo una parcela de memoria.
PARMETROS DE GESTIN DE MEMORIA
Antes de nada, es importante tener en cuenta que los parmetros de gestin de memoria
son, en la mayora de los casos, especficos de la maquina virtual. As, el parmetro -Xlp es
exclusivo de la maquina virtual implementada por IBM y se puede utilizar exclusivamente con
esta.
Aunque hay un montn de implementaciones de JVMs, en la prctica, solo 3 o 4 son utilizadas
en un porcentaje significativo y, en cualquier caso, siempre tendremos que probar nuestra
aplicacin con la implementacin de referencia, la de SUN, para evitar posibles problemas de
compatibilidades. Por eso, nos centraremos en los parmetros que se puedan utilizar con las
maquinas virtuales de SUN.
Los parmetros de gestin de memoria se identifican por un sistema de prefijos que indican
la naturaleza de dichos parmetros, as y segn SUN:
* Los parmetros que comienzan con -X no son estndar, no se garantiza su implementacin
en todas las implementaciones de la JVM y pueden cambiar en futuras versiones del JDK.
* Los parmetros que comienzan con -XX no se consideran estables (??) y no se
recomienda su uso para usuarios sin un conocimiento especifico.
Los principales parmetros de gestin de memoria son:
* Xms < tamao > establece la cantidad inicial de memoria
* Xmx < tamao > establece la cantidad mxima de memoria
* Xss < tamao > establece el tamao mximo de pila de cada hilo JAVA
Es decir, si quisiramos arrancar nuestra aplicacin con una cantidad de memoria asignada
de 64MB y queremos que llegue a utilizar un GB, por ejemplo, tendramos que lanzar un
script de la siguiente manera:
java -Xms64m -Xmx1024m nombre de nuestra aplicacin
Es importante conocer en profundidad que implican y para que se utilizan cada uno de estos
parmetros:
* Los parmetros Xms y Xmx establecen el tamao inicial y mximo de la cantidad de
memoria que la JVM utilizar para ejecutar programas java pero, esto no implica que nuestro
proceso java ocupe en memoria un tamao mximo como el establecido en el parmetro
Xmx. Como se ha especificado antes, la JVM es un proceso en si mismo y, como tal, necesita
memoria para poder cargar su cdigo y datos. Por tanto, un proceso java puede llegar a
ocupar mas espacio en memoria que el determinado en Xmx.
* El parmetro Xss sirve para determinar cual es la cantidad de memoria mxima que podr
utilizar un hilo ejecutado dentro de la maquina virtual. Para aquellos que no estn
familiarizados con la gestin de hilos, pondremos un ejemplo de sencilla comprensin:
imaginemos una aplicacin web desarrollada en java. Esta aplicacin web tendr sus datos
comunes y ocupar X espacio en memoria. Cada vez que alguien haga una peticin a nuestra
pgina web, se crear un hilo de ejecucin independiente que tendr sus propios datos (por
ejemplo, los datos de un formulario de registro en nuestra pgina) y que no sern
compartidos por el resto de hilos que se estn ejecutando en dicho momento (nuestra pgina
web no es monousuario puede tener un montn de usuarios concurrentes). Bueno, en este
caso, toda la memoria que utilice cada uno de los hilos se suma para el cmputo de memoria
global determinado por el parmetro Xmx pero, adems cada hilo comprueba que no supere
el mximo de memoria que determina el parmetro Xss. Si se supera, se lanza un
StackOutOfMemoryError.
Un caso comn y conocido donde se puede dar un StackOutOfMemoryError es a la hora de
usar reflexin en procesos XSLT por lo que, probablemente tengamos que subir el tamao
mximo de pila por hilo si utilizamos este tipo de tecnologa.
PARMETROS AVANZADOS DE GESTIN DE MEMORIA
Hasta ahora, hemos visto los parmetros ms bsicos de gestin de memoria pero hay
muchsimos ms. Vamos a centrarnos en dos de los ms importantes o, lo que es lo mismo,
de los que pueden solucionarnos problemas tanto de rendimiento como de funcionamiento
(seamos sinceros, nadie se interesa por esto hasta que el marrn le estalla entre las manos).
El problema es que, antes de poder especificar los comandos, tendremos que tragarnos algo
de literatura para comprender de que estamos hablando.
EL GARBAGE COLLECTOR
Toda mquina virtual viene con un recolector de basura o Garbage Collector. Este maravilloso
invento es el que consigue que los programadores java nos olvidemos por completo de tener
que lidiar con la gestin de la memoria (y es el culpable, por otro lado, que todo este tema
nos suene tan raro y distante y de ah este articulo).
El Garbage Collector libera el espacio de memoria ocupado por objetos que no van a volver a
ser utilizados. El proceso de localizacin y eliminado de esos objetos puede ser tan pesado
que llegue a parar una aplicacin hasta su conclusin, por lo que es especialmente
importante que lo configuremos correctamente.
La JVM divide el espacio en generaciones o particiones en los que poder aplicar sofisticados
algoritmos de recoleccin. Cuando alguno de estos espacios se llena, se fuerza una
recoleccin de objetos y, la eficiencia de este sistema se basa en que la mayora de los
objetos tienen una vida til muuuy corta. El espacio en memoria, se divide generalmente en
dos particiones: la nueva y la vieja generacin.
Cuando el tamao de la nueva generacin se llena, se invoca una recoleccin de objetos muy
rpida (GC) que acaba con los objetos que no vayan a ser utilizados y que traspasa a la vieja
generacin los objetos con vida. Cuando la vieja generacin se llena, se invoca una
recoleccin completa (Full GC) que implica a toda la memoria y que es mucho ms lenta que
la recoleccin rpida. Para entender un poco mas grficamente de lo que estamos hablando,
veamos unas trazas de una JVM:
[GC 50650K->21808K(76868K), 0.0478645 secs]
[GC 51197K->22305K(76868K), 0.0478645 secs]
[GC 52293K->23867K(76868K), 0.0478645 secs]
[Full GC 52970K->1690K(76868K), 0.54789968 secs]
En estas trazas se puede ver cmo, tras la primera recoleccin rpida (GC), se pas de
50650Kb usados a 21808Kb (de un total de 76868Kb que es el espacio asignado mediante
-Xmx). Tambin se puede ver cmo, tras la recoleccin completa (Full GC) se pas a un uso
de tan solo 1690Kb pero, a cambio de casi medio segundo de inactividad de nuestra
aplicacin, que es lo que tardo la recoleccin completa en llevarse a cabo.
Por tanto, no parece tener mucho sentido que tengamos un espacio de 4GB asignado a
nuestro proceso java y un espacio de 2MB -que es lo que viene asignado por defecto- para
nuestra nueva generacin. Normalmente, se recomienda que pongamos el tamao de la
nueva generacin que queramos mientras no supere el tamo determinado en -Xmx y, como
buena prctica, se recomienda asignar la mitad del espacio total de memoria (Ej. java
-Xmx1024m -Xmn512m nombre de nuestra aplicacin). As:
* Xmn < tamao > establece la memoria asignada para la nueva generacin.
Tambin se puede forzar la recoleccin mediante una llamada al sistema en java con
System.gc() pero, no se recomiendo su uso porque fuerza recolecciones completas e impide
la escalabilidad de los grandes sistemas.
LA MEMORIA PERMANENTE
Un concepto que, a veces, no queda muy claro es que todo esto de lo que estamos hablando
se refiere a memoria voltil, es decir memoria ocupada por datos con una esperanza de vida
mas o menos larga pero, en ningn caso, pensados para ser utilizados durante todo el tiempo
de ejecucin de nuestro proceso. Sin embargo, si hay datos permanentes que utilizar
nuestro proceso java.
Estos datos (classes, libreras, etc.) se almacenan en la memoria permanente que funciona
adicionalmente al espacio establecido por nosotros para la memoria voltil mediante el
parmetro -Xmx.
Que para que se utiliza esto realmente? Para la carga y descarga de classes dinamicamente
y, cuando alguien se pregunte que clases son esas que se cargan dinamicamente debe
recordar que nuestras JSPs se convierten en classes dinamicamente segn se van invocando
(aunque se pueda efectuar una precompilacin para ganar en rendimiento) y que las libreras
invocadas por nuestras aplicaciones tambin utilizan este espacio.
Cmo puede afectarnos esto? Bueno, la JVM establece por defecto un tamao mximo de
64mb para la memoria permanente. Si nuestra aplicacin empieza a generar clases como si
no hubiera maana (nadie duda de que todos nosotros hace aplicaciones con TRILLONES de
usuarios concurrentes) y llenamos este espacio en memoria, forzaremos una recoleccin
completa del Garbage Collector que penalizar el rendimiento de nuestra aplicacin. En un
escenario ms real, si nos hemos dedicado a agregar y usar libreras y libreras con sus
dependencias y nuestra memoria permanente no puede cargar todas las que necesitamos,
daremos con un OutOfMemoryError que nos romper el Chi a nosotros y a nuestros usuarios
(no te digo ya a nuestro jefe). No parece que tenga muchos sentido, por otro lado, que le
demos a nuestra mega-aplicacin 2GB de memoria voltil y la dejemos con 64mb para cargar
clases y libreras verdad?. As:
* XX:PermSize=< tamao > establece el tamao mnimo de la memoria permanente
* XX:MaxPermSize=< tamao > establece el tamao mximo de la memoria permanente
Si, por ejemplo, queremos utilizar 128mb para nuestra memoria permanente, ejecutaremos
algo como java -Xmx1024m -Xmn512m -XX:PermSize=128m nombre de nuestra
aplicacin)
Es importante recalcar que la memoria permanente es adicional a la memoria voltil
establecida por el comando -Xmx. Por eso, si arrancamos un proceso java con un permSize de
256mb y un -Xms de 256mb, el espacio total de memoria usada ser de mas de 512mb (256
de memoria voltil + 256 de memoria permanente + la memoria que utilice la maquina
virtual en si) Ej.