Descripción de las fugas de memoria en una aplicación de Android

Soy bastante nuevo en la programación Java, con mucha experiencia C ++, y estoy leyendo acerca de cómo las referencias pueden conducir a pérdidas de memoria en las aplicaciones de Android. Esta explicación me ha confundido. En "Lesson # 2" dice:

El punto es que la Actividad no sabe que la vida útil de SomeObject finalizará cuando finalice la instancia de la Actividad. Si ese objeto permanece en la memoria, mantendrá esa actividad en la memoria […] también.

Como lo veo (probablemente incorrecto, por favor, corrija), cuando la actividad termina, SomeObject es destruido (suponiendo que no existe otra referencia a él). La actividad hace referencia a SomeObject , no al revés. No veo por qué se filtra nada aquí, mucho menos toda la actividad.

Tiene que ver con el hecho de que están creando una clase anónima para EventListener.

 public void onResume() { super.onResume(); SomeObject object = new SomeObject(); object.setSuccessListener(new EventListener<Boolean>() { public void onEvent(Boolean response) { Log.d(TAG_NAME, "Valid response? "+response); } }); SomeObjectManager.getSingleton().addObject(object); } 
  • Se ha indicado explícitamente que esto se está haciendo en el Activity onResume ().

  • Las clases anónimas (así como las clases internas no estáticas) tienen una referencia implícita a su clase circundante. Así que en este caso, el EventListener tiene una referencia a la actividad en sí.

  • Por lo tanto, el SomeObject tiene una referencia a la actividad porque tiene una referencia a la clase anónima que implementa EventListener.

Aquí está el texto antes de la cita que usted hizo referencia en su pregunta:

Por ejemplo, en el ejemplo anterior: hemos adjuntado una referencia a nuestra instancia de actividad a algún objeto, presumiblemente persistente, y en un gestor en alguna parte. La cuestión es…

Por lo tanto, la clase SomeObjectManager, que no desaparece cuando la actividad se destruye, contiene una referencia a SomeObject y SomeObject contiene una referencia al EventListener, que a su vez hace referencia a la Activity.

Así que cuando usted dice:

Como lo veo (probablemente incorrecto, por favor, corrija), cuando la actividad termina, SomeObject es destruido (suponiendo que no existe otra referencia a él). La actividad hace referencia a SomeObject, no al revés.

La falla en esa lógica es que SomeObject hace referencia a la actividad, a través de EventListener.

¿Eso ayuda?

Aquí está la respuesta: ¿Cómo se escapa?

Si puede hacer eso, ejecute esto en el depurador y establezca el punto de interrupción en:

 Log.d(TAG_NAME, "Valid response? "+response); 

Ahora echa un vistazo a qué miembros tiene la instancia 'this'. En particular, usted está interesado en this$0 .

Así que la llamada es importante:

 objectFromBefore.setSuccessListener(null); 

Ver qué pasa antes de eso:

 object.setSuccessListener(new EventListener<Boolean>() { public void onEvent(Boolean response) { Log.d(TAG_NAME, "Valid response? "+response); } }); SomeObjectManager.getSingleton().addObject(object); 

Ahora la cadena es:

SomeObjectManager -> singleton -> listofObjects -> objeto

Y para el objeto:

Object-> successListeners-> anonymous EventListener-> este $

Este $ aquí es su instancia externa que es la actividad.

Desafortunadamente, es MUY fácil vaciar una actividad. Algunos desarrolladores Android que conozco son felices (ya veces deliberadamente) ajenos a este hecho. Felicitaciones a usted por cuidar lo suficiente para saber que desea aprender más para evitar esta situación.

Algunas maneras comunes en las que puedes perder una actividad

1) establecer / añadir / registrar su Actividad como oyente o observador y olvidarse de establecer (null) / quitar / anular el registro de la Actividad.

2) Entregar una referencia a su Actividad desactivada a cualquier cosa que se sostenga sobre ella usando una referencia estática y sin borrar la referencia estática. (Singletons son un ejemplo de esto)

3) Uso de clases internas no estáticas. (Manejadores anónimos de clase interna son un ejemplo de esto)

Algunas cosas que puede hacer para evitar este tipo de fugas

1) Recuerde establecer (null) / quitar / anular el registro de su actividad

2) Como parte de su diseño de software, hornee en sus componentes que tratan con su actividad el concepto del ciclo de vida de la actividad.

3) Haga que las clases internas estén estáticas, y donde necesite una referencia a la clase externa, use WeakReferences

4) Utilice el contexto de la aplicación cuando sea posible en lugar de su contexto de actividad.

Algunas circunstancias comunes bajo las cuales tu actividad será destruida y recreada

1) Si permite cambios de orientación en su aplicación, la actividad se destruirá y volverá a crear al cambiar de retrato a paisaje y viceversa.

2) Si sale de su aplicación utilizando el botón de retroceso del dispositivo, la actividad actual se destruirá (aunque la aplicación siga funcionando).

3) Aunque es más raro, Android puede matar su actividad a voluntad para liberar recursos y mantener el dispositivo sensible al usuario.

Debe familiarizarse con el Monitor de dispositivos de Android Studio, la herramienta hprof-conv y la Herramienta Eclipse Memory Analyzer. La forma más fácil que he encontrado para probar mi aplicación para ver si se está filtrando una actividad es el perfil de la memoria que en el Monitor de dispositivos mientras que ir a la aplicación, salir de ella con el botón de nuevo dispositivo y volver a la aplicación Haciendo clic en su icono en la bandeja de aplicaciones o en ir a los últimos. Repita esto varias veces y luego cree un archivo de volcado de memoria. Ejecute la herramienta hprof-conv en este archivo de volcado para convertirlo en un formato MAT puede entender y luego abrirlo en MAT.

Hay muchos tutoriales por ahí en conseguir un perfil de memoria y utilizando MAT. Simplemente haga una búsqueda en la web.

  • Cómo depurar la pérdida de memoria donde las instancias de excepción en el volcado heap no tienen referencias entrantes?
  • ¿Se trata de una fuga de contexto de Android?
  • ¿Puede un oyente de ViewTreeObserver no eliminado causar fugas de memoria?
  • Cómo corregir un "SQLiteConnection para la base de datos gms" que se filtró
  • Mi aplicación Android consume demasiada memoria
  • Herramienta de análisis de memoria en android?
  • Fuga de AdActivity en AdMob (SDK 7.0) para Android
  • Sqlite base de datos FUGA ENCONTRADA excepción en android?
  • Error de memoria de mapa de bits - Android
  • Android: EditText causando una pérdida de memoria
  • Android - Firebase - ¿Necesito eliminar CADA oyente?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.