java - ¿Por qué aumenta la memoria dinámica al relanzar una actividad?
android memory-leaks (5)
¿Es posible que este 0.08 MB de almacenamiento dinámico siempre se asigne (y no se pueda coleccionar por el> GC) sin importar lo que haga? Si no, ¿alguna idea de lo que podría estar causando esto?
Los 0.08MB de Heap, si no se utilizan, serán recuperados cuando el sistema considere que lo necesita. Garbage Collection no ocurre tan pronto como se llama a System.gc (), sino más bien como una solicitud para que GC suceda tan pronto como sea posible. A menudo hay un MUCHO tiempo entre la asignación de un objeto y su eliminación de la memoria. La especificación de la máquina virtual Java y la especificación del lenguaje Java especifican la duración del objeto en las siguientes etapas:
- Creado
- En uso (muy accesible)
- Invisible
- Inalcanzable
- Recogido
- Finalizado
- Desasignado
Tenga en cuenta que cuando un objeto es inalcanzable, simplemente se convierte en un candidato para la recolección de basura, como y cuando puede suceder. Incluso con una JVM pequeña como la de Dalvik, no creo que un objeto experimente toda la vida en un lapso de tiempo tan breve. GC es una operación costosa, por lo que se realiza solo cuando es necesario.
Si tiene objetos que necesitan ser eliminados de la memoria rápidamente (por alguna razón), intente con WeakReference. O tal vez podría proporcionar un poco más de contexto sobre lo que está tratando de hacer, y alguien podría ayudarlo mejor de esa manera.
Para obtener más información sobre cómo sucede GC en Java, este es un artículo bastante bueno
Esta pregunta se refiere a la memoria en Android.
Mi método:
Tengo dos actividades, A y B. De A, lanzo B así:
Intent i = new Intent(A.this, B.class);
startActivity(i);
En el botón, haga clic en B, hago esto:
B.this.finish();
- En B, anulo el método onDestroy y establezco todas las referencias a nulo.
- No asigno nueva memoria en el método onResume de A.
- No estoy filtrando un contexto.
- No estoy usando múltiples hilos.
- No estoy usando servicios.
- Todas las variables en B son variables de clase privadas, y todas están configuradas en nulo en el onDestroy de B.
- Además, ImageViews en B tiene su fondo establecido nulo en el onDestroy de B.
- Estoy seguro de que B se destruye.
El resultado:
Cuando estoy en la Actividad A, la memoria del montón está en 7.44 MB. Luego, cuando comienzo B y llamo a finalizar en B (y, por lo tanto, regreso a A), el montón se incrementa en 0.16 MB. Repitiendo este proceso nuevamente, el montón se incrementa en 0.08 MB cada vez.
- No estoy mirando el límite del montón, estoy mirando el montón asignado.
- Llamaré a System.gc () al final del método onDestroy de B.
Información adicional:
-He utilizado MAT para analizar las asignaciones de memoria y tratar de encontrar esta fuga. Algo extraño es que la Actividad B parece tener 5 instancias. Como sucede, estaba repitiendo el proceso startActivity / finish 5 veces. La entrada inferior es la Actividad, los otros son oyentes en la actividad:
Y esta es una captura de pantalla del árbol dominador. No puedo encontrar nada inusual o sospechoso.
-He visto ambos videos de Google IO sobre el uso de memoria (y fugas).
Pregunta:
¿Es posible que este 0.08 MB de almacenamiento dinámico siempre se asigne (y no se pueda coleccionar por el GC) sin importar lo que haga? Si no, ¿alguna idea de lo que podría estar causando esto?
Actualizar:
Traté de iniciar la actividad B sin configurar una vista de contenido en B. Esto significa que B es una actividad completamente vacía. El resultado fue que la memoria del montón NO aumentó cuando estoy relanzando la actividad varias veces. Tenga en cuenta, sin embargo, que esto no es una solución. Debo poder establecer una vista de contenido.
scorpiodawg: Traté de ejecutar mi aplicación en un emulador, y el montón aún crece. Buen intento sin embargo.
ntc: Cambié todas las ocurrencias de "esto" a "getApplicationContext ()" donde era posible. No pude llamar a setContentView (getApplicationContext ()); porque setContentView quiere una referencia a un archivo de diseño, no a un contexto. Lo que hice en cambio fue crear un archivo de diseño vacío y llamar a setContentView (emptylayout); en el método onDestroy de la Actividad B. Eso no ayudó.
Traté de eliminar todo el código para que solo se llame a setContentView (mylayout). Problema persistido Luego eliminé todos los elementos de la interfaz gráfica de usuario en el archivo XML de diseño. Problema persistido Lo único que quedaba eran las vistas del contenedor, un par de anidados lineales, relativos y scrolllayouts. Traté de eliminar la configuración del atributo "android: scrollbarDefaultDelayBeforeFade" en la barra de desplazamiento. El resultado fue excelente, la fuga de memoria se había desvanecido. Luego devolví todo el código que eliminé previamente, pero no configuré el atributo "android: scrollbarDefaultDelayBeforeFade" y la fuga de memoria volvió. Qué extraño es eso?
Lo que creo que es, es una pregunta típica de Java. Y matar una actividad no significa que sus objetos asociados se eliminen del heap
, incluso si están en tierra perdida (su referencia es nula). porque es completamente dependiente de la máquina virtual cuando llama a Garbage collector
(Independientemente de lo que diga System.GC()
). entonces, cuando la condición es casi como de memoria, la llama y la limpia (no puede estar seguro de nuevo, puede ser inmediatamente después de que su referencia sea null
), así que no creo que deba preocuparse por eso.
editado: llamar a setContentView(getApplicationContext);
y siempre que sea this
palabra clave para pasar un contexto, cámbiela a this.getApplicationContext()
Parece que tienes una pérdida de memoria dentro de esa actividad.
Probablemente está filtrando el contexto (la actividad en este caso). Por lo tanto, asegúrese de que todas las referencias al contexto se estén limpiando cuando llame al método onDestroy en la actividad. Más detalles aquí .
También eche un vistazo a posibles observadores de contenido que no estén desregistrados cuando termine la actividad.
Si tiene 5 instancias de actividad B, entonces no está administrando la pila de actividades correctamente. Encuentro que la mejor manera de verificarlo es con el comando CLI:
adb shell dumpsys meminfo ''tu nombre de paquete de aplicaciones''
Tuve un problema similar en un proyecto de dos actividades cuando cambié entre ellos. Cada vez que cambio recibí una nueva instancia en la pila como lo revela el comando anterior. Luego establecí los indicadores de las actividades iniciadas en FLAG_ACTIVITY_REORDER_TO_FRONT con un código como:
Intent i = new Intent("com.you.yourActivityB");
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);
Una vez que hice esto, el comando adb shell no mostró más instancias de mis dos actividades cuando cambié de una a otra.