android listview memory-leaks android-audiomanager

Android Context Memory Leak ListView debido a AudioManager



memory-leaks android-audiomanager (8)

El motivo más común que encontré en mi aplicación se debió a la inicialización de algunos componentes a través del archivo XML. Cuando haces eso, el Activity Context se inyecta, pero a veces todo lo que necesitas es un ApplicationContext . Con respecto a la vista web en Android, esta técnica me ayudó mucho.

Tengo un ListView y espero que se borre de la memoria cuando finalice la actividad. Sin embargo, parece que está goteando. Cuando pathToGC el volcado de memoria y obtengo el pathToGC para el ListView , obtengo lo siguiente:

Class Name | Shallow Heap | Retained Heap android.widget.ExpandableListView @ 0x4063e560 | 768 | 39,904 |- list, mList com.hitpost.TeamChooser @ 0x405f92e8 | 176 | 1,648 | ''- mOuterContext android.app.ContextImpl @ 0x40657368 | 160 | 304 | ''- mContext android.media.AudioManager @ 0x40662600 | 40 | 168 | ''- this$0 android.media.AudioManager$1 @ 0x406626b0 Unknown| 24 | 24

Veo este mismo contexto goteando en muchos de mis ListView''s . El truco es que no estoy usando AudioManager en ninguna parte de mi aplicación, el sonido no proviene de la aplicación. Por favor ayuda, me está volviendo loco. Obviamente, tratando de averiguar por qué sucede esto y cuál podría ser el problema raíz.


Esta es una actividad muy básica que replica el problema (al menos en Android 4.0.3)

public class MainActivity extends Activity { int image[]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // setContentView(R.layout.activity_main); image = new int[1000 * 1500 * 4]; } }

Como puede ver, no hay vistas o Layots asociados con la actividad, también configuré el perfil "Silencioso" en la Configuración de sonido del sistema y desactivé "Vibrar al tocar".

Ahora, después de unos pocos (5-7 dependiendo de su heapSize), la actividad se reinicia y genera el java.lang.OutOfMemoryError al intentar crear una nueva matriz.

07-27 19:54:10.160 22542-22542/? D/dalvikvm﹕ GC_FOR_ALLOC freed 6K, 1% free 56040K/56391K, paused 25ms 07-27 19:54:10.190 22542-22542/? D/dalvikvm﹕ GC_BEFORE_OOM freed 23449K, 43% free 32591K/56391K, paused 30ms 07-27 19:54:10.260 22542-22543/? D/dalvikvm﹕ GC_CONCURRENT freed 0K, 1% free 56029K/56391K, paused 3ms+3ms 07-27 19:54:11.850 22542-22542/? D/dalvikvm﹕ GC_FOR_ALLOC freed 6K, 1% free 56040K/56391K, paused 20ms 07-27 19:54:11.880 22542-22542/? D/dalvikvm﹕ GC_BEFORE_OOM freed <1K, 1% free 56040K/56391K, paused 29ms ... Out of memory on a 24000016-byte allocation.

Dumping .hprof También vi 2 actividades, una de ellas está en manos de AudioManager.

Llamar al "montón de actualización" y luego recoger la basura en el monitor del dispositivo Android realmente elimina la actividad de la memoria, eso es lo que indica la logcat en este procedimiento

07-27 19:44:23.150 85-85/? I/DEBUG﹕ #06 pc 000382cc /system/lib/libdvm.so (dvmCollectGarbageInternal(GcSpec const*)+1204)

También he intentado construir la versión de lanzamiento del apk y se comporta de la misma manera. Así que no es el depurador el que tiene la referencia.

Esto me parece como un error en Android. La solución alternativa sería llamar explícitamente a image = null en OnStop () o onFinish () de la actividad. Esto, por supuesto, no es conveniente.


Hay varias referencias a AudioManager en tu código que no creas activamente. Por ejemplo, cada View que se puede hacer clic puede tener una para reproducir en los sonidos de clic [ source ]. Supongo que ese es el enlace.

El código parece que no crearía referencias a AudioManager si deshabilitas los sonidos de clic en tu Configuración. Puedes intentarlo y comprobar si todavía hay una fuga.

El motivo de su fuga podría ser que se aferra a algún objeto de View en su código de ListView (¿Adaptador?). Si los mantiene cerca, es posible que tenga una View que tenga una reference AudioManager y que mantenga una referencia de Context .


Me gustaría compartir mi experiencia con respecto al mismo problema, mantenía algunas actividades en la pila por defecto y no las estaba terminando.

Para esas actividades, obtuve lo mismo que se mencionó anteriormente en el informe hprof.

Una vez que terminé ya no usé Actividades, las referencias anteriores no llegaron. Simplemente termine su actividad cuando ya no sea necesaria, luego se resolverá este problema.


No relacionado con la fuga de OP, pero para las personas que vienen aquí debido a que AudioManager causa fugas:

Si ve esta fuga porque está utilizando VideoView, probablemente se deba a este error: https://code.google.com/p/android/issues/detail?id=152173

VideoView nunca libera AudioManager si el video se está cargando.

La solución es, como se menciona en el enlace, crear VideoView manualmente usando ApplicationContext.

Editar: esta solución funcionará, hasta que ... si el decodificador de video dice que el video tiene un problema de codificación. VideoView intenta abrir un AlertDialog usando el contexto de la aplicación. Que sucede un choque.

Lo único que puedo evitar es seguir creando la vista de video usando el contexto de la actividad, y en activity.onDestroy, establezca el mContext de AudioManager al contexto de la aplicación usando la reflexión.

Nota: debe obtener el AudioManager utilizando activity.getSystemService (Context.AUDIO_SERVICE) en lugar de activity.getApplicationContext.getSystemService (Context.AUDIO_SERVICE), ya que AudioManager es una variable miembro de Context (obtendrá una instancia incorrecta de AudioManager si lo obtiene de contexto de la aplicación).

Por último, puede preguntarse por qué una variable miembro (AudioManager) impide que la clase (Actividad) se recoja. Desde el analizador de memoria, muestra que AudioManager es propiedad de pila nativa. Así que AudioManager de alguna manera no se limpió correctamente.


Puede utilizar el contexto de la aplicación para evitar fugas en este caso. No sé por qué, pero cuando comencé a usar el contexto de la aplicación, el problema desapareció.


Si su aplicación falla debido a una pérdida de memoria, puede evitar este bloqueo utilizando try - catch (java.lang.outofmemory). El hecho es que la propia JVM llama a GC, por lo que el programador no tiene control sobre esto. Puede instalar su aplicación en la tarjeta SD, en este caso se utilizará la memoria de la tarjeta SD. No se producirá una pérdida de memoria.

Simplemente vaya a su archivo de manifiesto, debe haber versión no. nombre de la versión, también debe haber "Ubicación de instalación", que sea "preferExternal".