Administración de memoria en java

65
Administración de memoria en Java http://javacuriosities.blogspot.com.ar/

description

En esta presentación cubrimos el modelo de memoria del JDK 5/6/7, a partir de JDK 8 hay un cambio en el modelo de memoria, así que no toda la presentación seria valida, aunque algunos conceptos se mantienen.

Transcript of Administración de memoria en java

Page 1: Administración de memoria en java

Administración de memoria en Java

http://javacuriosities.blogspot.com.ar/

Page 2: Administración de memoria en java

Temario ¿Qué es la memoria?

¿Quién esta a cargo del manejo de la memoria en Java?

Áreas de memoria (Runtime Data Areas)

- Stack

- Heap Área

- Non-Heap Área

¿Qué pasa cuando ejecutamos nuestro programa Java?

Ciclo de vida de los objetos

Size of tipos primitivos vs Wrappers

Size of Objetos

Modelo de memoria de la JVM y sus parámetros

Garbage Collector

¿Que es un OOM (Out Of Memory)?

¿Qué tipos de OOM podemos encontrar?

Administración de memoria en Java

Page 3: Administración de memoria en java

¿Que es la memoria?

La memoria es la parte utilizada por los sistemas informáticos para

almacenar información en tiempo de ejecución, o sea estamos hablando de

memoria volátil, por lo cual su contenido se pierde cuando se apaga el

equipo.

Administración de memoria en Java

Page 4: Administración de memoria en java

¿Quién esta a cargo del manejo de la memoria en Java?

La JVM (Java Virtual Machine) es la encargada de ejecutar nuestros

programas Java, pero a su vez es la que esta a cargo de reservar, asignar

y liberar la memoria utilizada por nuestra aplicación.

La arquitectura de la JVM contiene diversas partes las cuales cumplen

distintos objetivos al referirnos al manejo de memoria debemos mencionar

estamos hablando del área llamada ‘Runtime Data Areas’

Administración de memoria en Java

Page 5: Administración de memoria en java

Administración de memoria en Java

Estructura de la JVM

Page 6: Administración de memoria en java

Áreas de memoria (Runtime Data Areas)

Administración de memoria en Java

Page 7: Administración de memoria en java

Stack

Administración de memoria en Java

Page 8: Administración de memoria en java

Administración de memoria en Java

Cada thread creado por la JVM posee su propio PC Register (Program

Counter) y su propio Stack Frame.

Program Counter

- Es el encargado de mantener un puntero a la instrucción que esta siendo

ejecutada en un determinado momento por un hilo en particular, se va ir

desplazando por el código.

Stack Frame

- Frame: Cada método invocado crea un nuevo frame, este es usado para

almacenar datos y resultados parciales, solo un frame esta activo a la vez. El

frame es destruido cuando finaliza la invocación del método esta puede ser de

manera normal o abrupta.

- Local Variables: Cada frame contiene un array con sus propias variables

locales.

- Operand Stack: Cada frame contiene una pila, cuando un nuevo frame es

creado este se encuentra vacío, en esta estructura se van alocando las

instrucciones a ejecutar.

Page 9: Administración de memoria en java

Heap Area & Non-Heap Area

Administración de memoria en Java

Page 10: Administración de memoria en java

Heap Area

Administración de memoria en Java

El Heap es el espacio de memoria en donde se almacenan las instancias

de clases (Objetos) y arreglos. Esta puede crecer o ser reducida

automáticamente bajo demanda. El Garbage Collector (GC) es el

encargado de reclamar el espacio que los objetos van liberando. Esta área

es compartida por todos los threads.

Podemos identificar las siguientes dos partes

Young Generation

- Eden Space: Esta es el área inicial donde se inicializan la mayoría de los

objetos.

- Survivor Space: En esta área se almacenan los objetos que han sobrevivido a

la recolección de basura en el Eden. En general esta área esta dividida en dos

partes From y To.

Old Generation

- Tenured Space: Contiene los objetos que han existido por un tiempo largo y

que han pasado por el Survivor space.

Page 11: Administración de memoria en java

Non-Heap Area

Administración de memoria en Java

Esta área incluye los objetos que son considerados parte de la JVM. Al

igual que el heap esta puede crecer o ser reducida automáticamente bajo

demanda. Dependiendo de la implementación de la JVM el GC puede

actuar sobre esta área o compactarla. Esta área es compartida por todos

los threads.

Podemos identificar las siguientes dos partes

Permanent Generation

- Este espacio contiene todos los datos reflectivos de la JVM como por ejemplo

clases y métodos. Además contiene la estructura por clase (Propiedades, Firma

de métodos e implementación de métodos). Esta área además contiene dos

espacios llamados Shared-RO and Shared-RW

Code Cache

- Contiene la memoria usada para el código compilado por el JIT compiler y

almacenado de código nativo

Page 12: Administración de memoria en java

Administración de memoria en Java

Runtime Constant Pool

Page 13: Administración de memoria en java

From Permanent Generation To Metaspace

Administración de memoria en Java

Debido a que algunas implementaciones no usan este espacio y usan

espacio nativo, la gente de Oracle decidió eliminar esta área y usar un

nuevo llamado Metaspace. Este cambio se espera para JDK 8.

Resize automático de esta área

Algunas cosas se movieron al Heap

Nuevo flag MaxMetaspaceSize

Recolección automática al alcanzar el valor definido antes

Page 14: Administración de memoria en java

Ejemplo

Administración de memoria en Java

HelloWorld.java

RuntimeConstantPool.java

Page 15: Administración de memoria en java

¿Qué pasa cuando ejecutamos nuestro programa Java?

Administración de memoria en Java

Page 16: Administración de memoria en java

Administración de memoria en Java

Page 17: Administración de memoria en java

Classloaders

Administración de memoria en Java

Bootstrap Classloader carga el API básica de Java e inicia el ‘System

Class Loader’.

El ‘System Classloader’ envía los archivos .class por medio de un stream

binario a la JVM.

Usando ese stream la JVM obtiene la siguiente información

- Constantes, literales.

- Paquetes, modificadores, variables estáticas.

- Información de atributos.

- Información de métodos.

- Referencias al Classloader y a la Clase.

Esta información es almacenada en el ‘Method Area’.

Se crea el Thread-Main el cual busca el método main (Recordar

que cada thread tiene su propio Stack).

El Program Counter va ejecutando el código, usando las distintas

áreas de memoria.

Page 18: Administración de memoria en java

Para recordar acerca de los Classloaders

Administración de memoria en Java

Delegation (Delegación): El Classloader actual siempre va a

delegar la tarea de carga la clase a su padre antes de intentar

cargarla el mismo.

Visibility (Visibilidad): Las clases cargadas por los Classloaders

padres son vistas por todos los hijos pero no de modo inverso.

Uniqueness (Unicidad): Una vez que la clase es cargada por

cualquiera de sus Classloaders padres, el hijo nunca volverá a

cargarla.

Configurable (Configurable): La mayoría de servidores de

aplicaciones crean sus propios Classloaders utilizando como

padre al System Classpath Classloader

Page 19: Administración de memoria en java

Ejemplo

Administración de memoria en Java

ClassLoaderDelegation.java

Page 20: Administración de memoria en java

Ciclo de vida de los objetos

Administración de memoria en Java

Class Loading

- La primera vez que se crea un objeto de esa clase.

- Cuando se accede a una propiedad o método estático de esa clase por primera vez.

Inicializadores estáticos

- Inmediatamente después de cargar la clase se ejecutan los inicializadores estáticos

de la clase.

Creación del objeto

Un objeto es una instancia de una clase, la creación de un objeto tiene tres

partes.

- Declaración

- Instanciación

- Inicialización

Uso del objeto

Limpieza (Método Finalize y luego GC)

Page 21: Administración de memoria en java

Ejemplo

Administración de memoria en Java

LifeCycle.java

Page 22: Administración de memoria en java

Size of tipos primitivos vs wrappers

Administración de memoria en Java

Primitive Type Size (Bytes) Wrapper Type Size (Bytes)

char 2 Character 16

byte 1 Byte 16

short 2 Short 16

int 4 Integer 16

long 8 Long 16

float 4 Float 16

double 8 Double 16

boolean 1 Boolean 16

Como se puede observar la diferencia entre usar tipos primitivos y

usar sus wrappers puede ser bastante grande.

Page 23: Administración de memoria en java

Ejemplos

Administración de memoria en Java

SizeOfPrimitives.java

SizeOfWrappers.java

Page 24: Administración de memoria en java

Size of Objetos

Administración de memoria en Java

Como vimos antes los wrappers pueden consumir mucha memoria,

pero lo importante es entender el porque de esto.

Reglas:

Objetos:

- El tamaño base de cualquier objeto es 8 bytes.

- El tamaño total de un objeto siempre es múltiplo de 8 (Esto se lo conoce como

padding)

Atributos:

- Si el tipo del atributo es primitivo ocupa el size que le corresponde.

- Si el tipo del atributo es un objeto, entonces ocupa 4 bytes porque es una

referencia.

Arrays:

- Array de primitivos ocupa: 8 (Base) + 4 (Length) + Length * size del tipo primitivo.

- Array de objetos ocupa: 8 (Base) + 4 (Length) + Length * 4 (Size de una

referencia).

Page 25: Administración de memoria en java

Shallow size vs. Retained size

Administración de memoria en Java

Figura 1:

Objeto 1: Retained size obj1, obj2, obj4

Objeto 2: Retained size obj2, obj4

Figura 2:

Objeto 1: Retained size obj1, obj2, obj3, obj4

Objeto 2: Retained size obj2, obj3, obj4

Page 26: Administración de memoria en java

Ejemplos

Administración de memoria en Java

SizeOfObjects.java

ShallowVsRetained.java

Page 27: Administración de memoria en java

Modelo de memoria de la JVM

Administración de memoria en Java

Debemos tener en cuenta que la máxima memoria que podemos asignar a un

proceso Java va a depender del Sistema Operativo (SO) y de la JVM que

estemos usando.

JVM 32 bits: Valor máximo aproximado 2GB.

JVM 64 bits: Valor muy superior a la de 32 bits. Aproximadamente (2^48).

Page 28: Administración de memoria en java

Parámetros de memoria

Administración de memoria en Java

Page 29: Administración de memoria en java

Administración de memoria en Java

-Xms = Mínimo tamaño del Heap.

-Xmx = Máximo tamaño del Heap.

-XX:NewSize = Tamaño inicial del Eden + Survivor Space.

-XX:MaxNewSize / -Xmn = Máximo tamaño de Young Generation.

-XX:PermSize = Mínimo tamaño del PermGen (Permanent Generation).

-XX:MaxPermSize = Máximo tamaño del PermGen (Permanent Generation).

Page 30: Administración de memoria en java

Parámetros JVM

Administración de memoria en Java

Parámetro Definicion Ejemplo

-Xms Minimo tamaño del Heap -Xms512M

-Xmx Maximo tamaño del Heap -Xmx512M

-XX:NewSize Tamaño inicial del Eden + Survivor Space -XX:NewSize=128M

-XX:MaxNewSize / -Xmn Máximo tamaño de Young Generation -XX:MaxNewSize=128M

-XX:NewRatio Ratio entre Young y Old generation -XX:NewRatio=3

-XX:SurvivorRatio Ratio entre Eden y Survivor -XX:SurvivorRatio=6

-XX:PermSize Mínimo tamaño del PermGen (Permanent Generation) -XX:PermSize=64M

-XX:MaxPermSize Máximo tamaño del PermGen (Permanent Generation) -XX:MaxPermSize=128M

-Xss -XX:ThreadStackSize Tamaño de cada stack de cada Thread -XX:ThreadStackSize=256k

-XX:MinHeapFreeRatio Indica el minimo de Heap libre antes de pedir memoria -XX:MinHeapFreeRatio=40

-XX:MaxHeapFreeRatio Indica el maximo de Heap libre antes de liberar memoria -XX:MaxHeapFreeRatio=70

-XX:TargetSurvivorRatio Indica hasta que porcentaje se puede llenar el Survivor antes de mover al Old -XX:TargetSurvivorRatio=90

Page 31: Administración de memoria en java

Ejemplos

Administración de memoria en Java

JVMParameters.java

MemoryViewer.java

Page 32: Administración de memoria en java

Administración de memoria en Java

La Recolección de basura automática es el proceso de buscar en la

memoria y liberar aquellos objetos que estén disponibles para ser

recolectados, podemos identificar dos tipos de objetos

Reachable (Objeto sobre el cual aun hay referencias) : Significa que alguna

parte de nuestro programa todavía mantiene una o mas referencias a ese

objeto.

Unreachable (Objeto el cual no puede ser referenciado): Ya no se hace

referencia en ninguna parte del programa no hay forma de obtener la

referencia a ese objeto. Así que la memoria utilizada por un objeto no

referenciado puede ser reclamada.

En un lenguaje de programación como C, asignar y desasignar la memoria

es un proceso manual. En Java, el proceso de cancelar la asignación de

memoria es manejado automáticamente por el recolector de basura.

Garbage Collector

Page 33: Administración de memoria en java

Garbage Collector Behaviour

Administración de memoria en Java

Page 34: Administración de memoria en java

Administración de memoria en Java

Línea #6 Línea #8

Línea #11

System.runFinalization(): Le sugiere a la

JVM a ejecutar el método finalize de los

objetos que están en la cola de finalización.

System.gc(): Le sugiere a la JVM ejecutar el

garbage collector para reclamar espacio y

liberar memoria.

Page 35: Administración de memoria en java

Administración de memoria en Java

Tipos de recolecciones

Existen dos tipos de recolecciones

Minor GC

- Ejecutado en el Young Generation, cuando el Eden se encuentra lleno o antes

de incrementar el espacio de esta área se ejecuta esta recolección. Aquí se usa

un algoritmo de copia.

Full GC

- Ejecutado en el Tenured Generation, cuando el Old se encuentra lleno se

ejecuta esta recolección o antes de incrementar el espacio de esta área. Aquí

se puede usar el algoritmos MSC(Mark- Sweep- Compact) o CMS (Concurrent

Mark Sweep), este ultimo no compacta los objetos luego de su ejecución lo cual

genera que pedir memoria sea un poco mas complejo. Incluye el PermGen en

su recolección.

Page 36: Administración de memoria en java

Administración de memoria en Java

Algoritmo de Copia (Paso 1)

Page 37: Administración de memoria en java

Administración de memoria en Java

Algoritmo de Copia (Paso 2)

Page 38: Administración de memoria en java

Administración de memoria en Java

Algoritmo de Copia (Paso 3)

Page 39: Administración de memoria en java

Administración de memoria en Java

Algoritmo de Copia (Paso 4)

Page 40: Administración de memoria en java

Administración de memoria en Java

Algoritmo de Copia (Paso 5)

Page 41: Administración de memoria en java

Administración de memoria en Java

Algoritmo de MSC (Paso 1)

Page 42: Administración de memoria en java

Administración de memoria en Java

Algoritmo de MSC (Paso 2)

Page 43: Administración de memoria en java

Administración de memoria en Java

Algoritmo de MSC (Paso 3)

Page 44: Administración de memoria en java

Administración de memoria en Java

Algoritmo de CMS

N° Fase Descripcion

1 Initial Mark

(Stop the World Event) Es una pausa pequeña donde todos los objetos "reachable" son marcados.

2 Concurrent Marking Busca objetos vivos mientras la aplicación se ejecuta en otro hilos.

3 Remark

(Stop the World Event) Busca los objetos que no fueron encontrados durante la parte 2.

4 Concurrent Sweep Remueve los objetos que son "unreachable", es importante notar que los objetos

"reachable" no son movidos, o sea no hay compactacion.

5 Resetting Se prepara para la siguiente ejecución limpiando las estructuras usadas.

Page 45: Administración de memoria en java

Administración de memoria en Java

Tipos de GC por áreas de memoria

Page 46: Administración de memoria en java

Administración de memoria en Java

Young Generation:

"Serial" corre en un solo hilo y es del tipo STW (Stop-the-world).

"Parallel Scavenge" corre en múltiples hilos y aunque es del tipo STW

(Stop-the-world), obtiene una mejor performance.

"ParNew" es igual que el "Parallel Scavenge" pero esta mejorado para

trabajar de forma concurrente con "CMS".

Tenured Generation:

"Serial Old" corre en un solo hilo y es del tipo STW, usa el algoritmo

Mark-Sweep-Compact.

"Parallel Old" corre en múltiples hilos, también es del tipo STW.

"CMS" corre de forma concurrente la mayor parte del tiempo y tiene

pequeñas pausas donde se ejecuta en forma STW.

Page 47: Administración de memoria en java

Administración de memoria en Java

Page 48: Administración de memoria en java

Administración de memoria en Java

Page 49: Administración de memoria en java

Administración de memoria en Java

GC Collectors

JVM Young Collector Tenured Collector

-XX:+UseSerialGC Serial Serial Old (MSC)

-XX:+UseParNewGC ParNew Serial Old (MSC)

-XX:+UseParallelGC Parallel Scavenge Serial Old (MSC)

-XX:+UseParallelOldGC Parallel Scavenge Parallel Old

-XX:-UseParNewGC

-XX:+UseConcMarkSweepGC Serial CMS + Serial Old (MSC)

-XX:+UseParNewGC

-XX:+UseConcMarkSweepGC ParNew CMS + Serial Old (MSC)

-XX:+UnlockExperimentalVMOptions

-XX:+UseG1GC G1

Page 50: Administración de memoria en java

Administración de memoria en Java

JVM Ergonomics

Desde el JDK 5.0 la JDK detecta en que tipo de maquina esta y cambia su

configuración, modo cliente o modo servidor.

Estos cambios incluyen:

- Configuración de memoria mínima y máxima para el Heap.

- Selección automática del GC.

- Activa el resize automático para el área Young y Tenured.

- Otras configuraciones adicionales.

Page 51: Administración de memoria en java

Administración de memoria en Java

Analizando el GC (Parámetros)

Parámetro Definicion

-verbose:gc Imprime informacion por consola del GC

-Xloggc:GCLogs.log Guarda la misma información que -verbose:gc en un archivo que le indiquemos pero además agrega mas detalle

-XX:+PrintGCDetails Imprime el detalle de cada recoleccion

-XX:+PrintGCDateStamps Imprime DateStamps para cada GC (Dia+Hora+Minutos+Segundos+Milisegundos)

-XX:+PrintGCTimeStamps Imprime el TimeStamp para cada recoleccion

Page 52: Administración de memoria en java

Administración de memoria en Java

Analizando el GC (Revisando el output)

Page 53: Administración de memoria en java

Ejemplos

Administración de memoria en Java

GCMXBean.java

GCDetails.java

Page 54: Administración de memoria en java

¿Que es un OOM (Out Of Memory)?

Administración de memoria en Java

Este es el error que se suele producir debido a que la JVM se

queda sin memoria disponible.

Existen varios tipos de OOM y en base a cual de ellos nos

estemos enfrentando sabremos si es porque la JVM se que sin

memoria en una área o en otra.

Page 55: Administración de memoria en java

Tipos de OOM

Administración de memoria en Java

java.lang.OutOfMemoryError: unable to create new native thread

- OOM en la memoria nativa, esta área no es controlada por nosotros sino que la maneja el SO (Sistema

Operativo).

Java 32-bit Native Heap = Max Process Size – Java Heap – PermGen

Java 64-bit Native Heap = Memoria Fisica & Virtual – Java Heap – PermGen

java.lang.OutOfMemoryError: Java heap space

- OOM en el Java Heap, esto se produce cuando tenemos demasiados objetos en memoria o tenemos

un posible Memory Leak (Fuga de memoria).

java.lang.OutOfMemoryError: PermGen space

- OOM en el PermGen Space, esto se produce porque estamos cargando muchas clases por nuestra

aplicación, o almacenando muchos String en la cache de constantes o en servidores de aplicaciones

donde intentamos desplegar la aplicación y los ClassLoader quedan referenciados.

java.langOutOfMemoryError: GC overhead limit exceeded

- Este error sucede cuando el GC esta gastando mucho tiempo en limpiar la memoria y la memoria

recuperada en muy poca.

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

- Este error sucede porque estamos intentando crear un vector mas grande que nuestro heap.

Page 56: Administración de memoria en java

Ejemplos

Administración de memoria en Java

OOMNativeHeap.java

OOMJavaHeapSpace.java

OOMPermGenSpace.java

OOMRequestArraySize.java

Page 57: Administración de memoria en java

OOM vs Memory Leak

Administración de memoria en Java

No todo OOM indica una fuga de memoria (Memory Leak)

- Puede haber una fuga de memoria.

- La aplicación puede necesitar mas memoria.

Page 58: Administración de memoria en java

Heap Dump

Administración de memoria en Java

Un Heap dump es una foto de la memoria de un proceso Java

en un determinado momento.

Dependiendo de la JVM el Heap dump puede contener una

información o otra, además en general antes de ejecutar el

volcado un recolección completa es ejecutada (Full GC).

Page 59: Administración de memoria en java

Obteniendo un Heap Dump

Administración de memoria en Java

Aplicación Externa

Alguna aplicación externa como VisualVM.

HeapDumpOnOutOfMemoryError

Cuando la aplicación arroje un OOM se generara un heap dump, usando el HeapDumpPath

configurado.

Jmap

Tool que viene incorporada en el jdk.

jmap -dump:file=<file-location> <pid>

Jmap (Desde la aplicación)

Podemos usar los MXBean para ejecutar el jmap desde la aplicación.

HotSpotDiagnosticMXBean(Usando Reflection)

Usando el DiagnosticMXBean para hacer el dump

Page 60: Administración de memoria en java

Heap Dump (Parámetros JVM)

Administración de memoria en Java

Parámetro Definicion Ejemplo

-XX:+HeapDumpOnOutOfMemoryError Activa la generacion de un Heap Dump frente a un OOM -XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath Indica el Path para el Heap Dump -XX:HeapDumpPath=C:\temp

Page 61: Administración de memoria en java

Ejemplo

Administración de memoria en Java

MainHeapDump.java

HeapDumpPath.java

Page 62: Administración de memoria en java

Analizando un Heap Dump (Puntos clave 1)

Administración de memoria en Java

Revisar memoria consumida y numero de instancias.

- Wrappers grandes consumidores de memoria.

Histogram

- Nos muestra la cantidad de objetos por cada clase.

Analizar el Dominator Tree

- Esta estructura nos muestra los objetos mas grandes, aquí debemos ver que la lista esta

compuesta de lo que esperamos, en general aquí podremos ver cache no liberadas.

Group By por clase

- Esta opción nos permite ver la memoria que consume cada clase, de esta forma

podremos detectar objetos que se repiten varias veces y consumen un gran volumen.

Group By por value

- En general para analizar si tenemos Wrappers duplicados.

Keep Unreachable objetcs

- Debemos prender esta opción en el MAT para que no elimine los objetos que serian

unreachables.

Object Query Language (OQL)

- Lenguaje de consulta que nos deja interactuar con los objetos del Heap.

Page 63: Administración de memoria en java

Analizando un Heap Dump (Puntos clave 2)

Administración de memoria en Java

Revisar GC Roots

- El Garbage collector recorre la memoria usando GC roots, lo cuales son porciones de memoria que

pueden ser accedidas desde afuera del Heap.

- Local Variables.

- Thread activos.

- Variables estáticas.

- Referencias JNI

Shallow size vs. Retained size

- Shallow size: Es el espacio ocupado por el objeto en si mismo.

- Retained size: Es el espacio ocupado por el objeto en si mismo mas la suma de todos los shallow sizes

que son accedidos directamente o indirectamente solo desde este objeto

Page 64: Administración de memoria en java

JDK Tools

Administración de memoria en Java

Jps

- Nos brinda información de los procesos Java corriendo en nuestra computadora y no

entrega el PID.

Jmap

- Nos ofrece información de las áreas de memoria del proceso Java indicado y además nos

permite generar Heap Dumps y Histogramas.

Jhat

- Herramienta de análisis del Heap, es experimental y puede no estar incluida en futuras

versiones.

Jstat

- Nos brinda información estadística sobre el proceso Java que le indicamos, esta

estadísticas incluyen tiempo del GC, JIT Compiler, Classloaders.

Jstack

- Ejecuta un Thread Dump o sea un volcado de cada Thread.

Jinfo

- Brinda información de configuración de un proceso Java.