Memory leaks
Un objeto es candidato a ser elegido por el garbage collector cuando ninguna referencia apunta hacia él.
Un memory leak se da cuando un objeto ya no es utilizado por la aplicación pero no puede ser barrido por el gc porque otro objeto apunta hacia él, esto hace que se quede colgado en memoria.
Object o = new Object
, el objeto será elegible por el gc hasta que ningún objeto apunte a él.Se utilizan cuando se desea tener una referencia hacia un objeto, pero esa referencia puede ser barrida en cualquier momento por el garbage collector. Un ejemplo clásico es un caché que desea sea barrido cuando la memoria se infle (a menudo se implementa con WeakHashMap).
En java las clases internas (no estáticas) y las clases anónimas tienen una referencia implicita hacia su clase externa.
Android puede destruir actividades y procesos, cuando destruye actividades se destruyen todos sus objetos, por lo que se tienen que regresar a su estado original antes de la destrucción. Cuando destruye el proceso completo, barre con todo incluidos miembros estáticos.
Una actividad es destruida cuando:
Android intenta mantener vivos los procesos de las aplicaciones, sin embargo en ocasiones el proceso completo de la aplicación puede ser destruido cuando android requiere memoria, a consecuencia de esto las variables estáticas pueden morir.
Las actividades y vistas tienen métodos para recuperar su estado y restaurarlo en una nueva instancia.
Cuando un proceso termina, android intenta volver a la misma actividad en donde se quedó antes de matar el proceso.
Todas las vistas tienen una referencia hacia la actividad donde son creadas. Por lo tanto, cuando muere la actividad también mueren todas las instancias de los componentes gráficos asociados a ella (vistas).
Para reproducir matar el proceso como lo haría android: Bajar la aplicación con el botón home, matar el proceso, dejar presionado home y elegir el recuadro de la app.
Referencia: Testing android resets
Cuando se rota la pantalla android destruye la instancia de la actividad (sin importar si tiene o no un memory-leak) y crea otra para ser utilizada. La consecuencia de que la actividad tenga un leak es que no podrá ser barrida la referencia por el gc y quedará colgada en memoria.
public void onResume() {
super.onResume();
SomeObject object = new SomeObject();
// obj->eventListener->actividad(implicitamente)
object.setSuccessListener(new EventListener<Boolean>() {
public void onEvent(Boolean response) {
Log.d(TAG_NAME, "Valid response? "+response);
}
});
// MemoryLeak: aquí sin darnos cuenta se ata la actividad hacia el singleton
// que vive durante todo el ciclo de vida de la app y no permite al gc
// barrer la actividad (el singleton apunta hacia ella).
SomeObjectManager.getSingleton().addObject(object);
}
onStop()
,onDestroy()
.getLastNonConfigurationInstance
: Hay que tener cuidado de no retornar objetos que tengan agarrado el contexto porque la consecuencia es un memory leak.Nota: Cuando un thread toma una actividad y no la suelta, se está creando un memory-leak sin embargo el thread soltará la actividad cuando termine su ejecucución y ésta podrá ser elegible y barrida por el gc.
Nota: Una variable estática no provoca memory leaks mientras no tome el contexto o alguno de sus objetos y no lo suelte.