Este documento discute los memory leaks en Android, incluyendo su definición, cómo funciona el garbage collector, patrones comunes de memory leaks como referencias estáticas y subprocesos, cómo identificar y solucionar memory leaks, y el impacto de memory leaks en el rendimiento de las aplicaciones.
2. | Copyright 2017
AGENDA
Funcionamiento del
Garbage Colector
¿Por qué los Memory
Leaks son malos?
¿Cómo identificar un
Memory Leak?
¿Qué es un Memory Leak?
¿Cuáles son los patrones
más comunes de los
Memory Leaks?
¿Cuál es el impacto de un
Memory Leak en
particular?
¿Cómo solucionar / evitar
los Memory Leaks?
3. | Copyright 2017
¿QUÉ ES UN
MEMORY LEAK?
• Una fuga de memoria, más conocida por
el término inglés memory leak, es un
error de software que ocurre cuando un
bloque de memoria reservado no es
liberado en un programa de
computación.
• Los memory leak se suman con el
tiempo, y si no se solucionan, el sistema
finalmente se queda sin memoria.
Definición
4. | Copyright 2017
FUNCIONAMIENTO
DEL GARBAGE
COLLECTOR
• Para asegurarse de que cada aplicación
en Android tiene suficiente memoria, el
sistema operativo necesita administrar
eficientemente la asignación de
memoria. En tiempo de ejecución
Android activa el “Recolector de Basura” -
Garbage Collector (GC) cuando la
memoria se agota. El propósito de GC es
recuperar la memoria mediante la
limpieza de objetos que ya no son útiles.
Garbage Collector
5. | Copyright 2017
SE LOGRA EN
TRES PASOS
1
2
3
Todos los objetos que no están
referenciados son marcados como
“garbage” y son borrados de la
memoria.
Se examina todas las referencias de
objetos en memoria de las raíces GC y
se marcan objetos activos que tienen
referencias de raíces GC.
Se reorganizan los objetos “vivos”
Garbage Collector
6. | Copyright 2017
SIN EMBARGO… • Cuando el código está escrito de manera
incorrecta de modo que los objetos no
utilizados se referencien de alguna
manera a objetos accesibles, el GC
marcaría objetos no utilizados como
objetos útiles y por lo tanto no sería capaz
de eliminarlos. Esto es un memoly leak.
Garbage Collector
7. | Copyright 2017
¿POR QUÉ LOS
MEMORY LEAKS
SON MALOS?
Ningún objeto debe permanecer en la
memoria más de lo que debería. Ellos
ocupan valiosos recursos que de otra
manera podrían ser utilizados para cosas
que proporcionan un valor real al usuario.
Memory Leaks
8. | Copyright 2017
¿POR QUÉ LOS MEMORY LEAKS SON MALOS?
Menos memoria utilizable estaría
disponible cuando ocurre un
memory leak. Como resultado, el
sistema Android activará eventos
GC más frecuentes. Los eventos
del GC son eventos “stop-the-
world”. Esto significa que cuando
ocurre un GC, la interfaz de
usuario y el procesamiento de los
eventos se detendrán.
En Android, la capacidad de
respuesta de las aplicaciones es
supervisada por los servicios del
sistema: Activity Manager y
Window Manager. Android
mostrará un diálogo ANR
(Application Not Responding)
para una aplicación en particular
cuando se detecte una de las
siguientes condiciones:
• No hay respuesta a un evento
de entrada (como presionar
teclas o eventos de pantalla
táctil) dentro de los 5 segundos.
• Un Broadcast Receiver no ha
terminado de ejecutarse en 10
segundos.
9. | Copyright 2017
¿POR QUÉ LOS MEMORY LEAKS SON MALOS?
Cuando una aplicación tiene
memory leaks, no se puede
recuperar la memoria de objetos
no utilizados. Como resultado, le
pedirá al sistema más
memoria. Pero hay un límite y el
sistema se negará a asignar más
memoria a la aplicación. Cuando
esto sucede, el usuario de la
aplicación obtendrá un “crash”
por de falta de memoria.
10. | Copyright 2017
¿CÓMO
IDENTIFICAR
UN MEMORY
LEAK?
Android Studio provee herramientas que
pueden ayudar a identificar Memory Leaks o
asegurarse que no hay Memory Leaks en
algún pedazo de código que parece
sospechoso.
Identificar Memory Leaks
11. | Copyright 2017
PASOS PARA IDENTIFICAR UN MEMORY LEAK
1. Compilar y ejecutar la
aplicación en un dispositivo o
emulador.
2. Utilizar la aplicación,
asegurándose de ejecutar las
Activities y/o Fragments que
pueden contener los Memory
Leaks.
3. Seleccionar Android Monitor >
Monitors > Initiate GC.
4. Ejecutamos “Dump Java
Heap”.
5. Android Studio nos genera un
archivo .hprof en donde nos
arma el árbol de instancias de
todos los objetos que existen
en ese momento en nuestra
aplicación.
6. A la derecha tenemos la
opción “Analyzer Tasks”
7. Seleccionamos “Detect
Leaked Activities” y el símbolo
de “Play”
8. Si la aplicación contiene
Memory Leaks en “Analysis
Results” veremos las Activities
que tienen Memory Leaks. Al
seleccionarlas, en “Reference
Tree” nos indica con azul en
donde está el Leak. También
podemos ver la cantidad de
referencias que, por lo general,
debe haber 1 sola referencia de
cada objeto en memoria, si
hay más de una instancia
puede ser indicio de un
Memory Leak.
12. | Copyright 2017
CUÁLES SON LOS
PATRONES MÁS
COMUNES DE LOS
MEMORY LEAKS
Existen muchas maneras de introducir
Memory Leaks en Android, pero se pueden
agrupar en 2 categorías
1. Leak una Activity a una referencia
estática.
2. Leak una Activity a un “worker thread”.
Patrones de Memory Leaks
13. | Copyright 2017
LEAK UNA ACTIVITY A UNA
REFERENCIA ESTÁTICA
Una referencia estática “vive”
mientras la aplicación esté en la
memoria. Una Activity tiene
ciclos de vida que normalmente
se destruye y vuelve a crear
varias veces durante el ciclo de
vida de la aplicación. Si se hace
referencia a una Activity directa
o indirectamente de una
referencia estática, la Activity no
será recolectada por el GC
después de que se destruya.
Ejemplo 1: Leak Activity a una
vista estática.
Ejemplo 2: Leak Activity a una
variable estática.
Ejemplo 3: Leak Activity a un
objeto singleton.
Ejemplo 4: Leak Activity a una
clase interna.
Ejemplo 5: Leak Activity a un
listener.
PARA RECORDAR
El modificador “static” se puede usar
con variables y/o métodos.
• Variable: Cuando se declara como
variable estática, solo hay una
variable, independientemente de
cómo se creen las instancias, esta
variable se inicializa cuando se
carga la clase.
• Método: Un método estático
puede ser accedido o invocado sin
la necesidad de tener que
instanciar un objeto de la clase.
Los métodos estáticos no pueden
ser accedidos desde un contexto
no estático.
14. | Copyright 2017
LEAK UNA ACTIVITY A UN
“ WORKER THREAD”
Un hilo de trabajo (worker
thread) puede “vivir” más que
una Activity. Si hace referencia a
una Activity directa o
indirectamente a partir de un
subproceso de trabajo que dura
más que la Activity, también se
genera un Leak del objeto
Activity.
Ejemplo 6: Leak Activity a un
thread.
Ejemplo 7: Leak Activity a un
handler.
Ejemplo 8: Leak Activity a una
AsyncTask.
El código se puede descargar
desde este repositorio
https://github.com/simtlix/And
roid-Memory-Leaks
Message #1
Message #2
Message #3
Message #4
Message #5
Message
Queue
Looper;
loop()
Handle
Message()
Send
Message()
Handler
Thread
Runnable #1
Message #1
THREAD: LOOPER: HANDLER
15. | Copyright 2017
¿CUÁL ES EL
IMPACTO DE UN
MEMORY LEAK
EN PARTICULAR
Lo ideal sería evitar escribir cualquier código
que causa memory leaks en primer lugar y
corregir todos los memory leaks existentes
en la aplicación. Pero en realidad, si se trata
de un código legacy y se necesitan priorizar
las tareas, incluyendo los memory leaks, se
puede evaluar la gravedad en los siguientes
aspectos:
1. ¿Qué tan grande es el Memory Leaks?
2. ¿Por cuánto tiempo reside el objeto con
leak en la memoria?
3. ¿Cuántos objetos se pueden eliminar?
Impacto de Memory Leak
16. | Copyright 2017
¿CÓMO
SOLUCIONAR /
EVITAR LOS
MEMORY
LEAKS?
Siguiendo estas recomendaciones se podrá
minimizar / evitar memory leaks en nuestras
aplicaciones.
Solucionar / Evitar Memory Leaks
17. | Copyright 2017
SOLUCIONAR / EVITAR MEMORY LEAKS
1. Tener mucho cuidado cuando decida tener una
variable estática en una clase de Activity. ¿Es
realmente necesario? ¿Es posible que la variable
estática haga referencia a la Activity directa o
indirectamente (indirectamente puede estar haciendo
referencia al objeto de clase interna, una vista adjunta,
etc.)? Si es así, ¿Se borra la referencia en Activity
onDestroy?
2. Cuando se pasa la Activity como referencia a un
objeto singleton, asegurase de entender lo que hace
el otro objeto con la instancia de Activity que se pasó.
Eliminar la referencia (definir la referencia como null)
si es necesario en Activity onDestroy.
3. Cuando se crea una clase interna en una Activity,
hacerla estática si es posible. Las clases internas y las
clases anónimas tienen una referencia implícita a la
clase que contiene. Así que si la instancia de la clase
interna / anónima vive más tiempo que la clase que
contiene, se está en problemas. Para evitar el riesgo de
Leaks, utilizar una clase estática en lugar de una clase
interna / anónima.
4. Si está escribiendo una clase y se necesita enviar una
referencia de una instancia a un “Listener” y no tiene
control de cómo la clase gestiona la referencia, puede
utilizar WeakReference para la referencia al
listener. WeakReference ayuda a que las referencias
sean eliminadas por el GC.
5. Siempre terminar los subprocesos de trabajo iniciados
en Activity onDestroy ().