Cómo manejar: java.util.concurrent.TimeoutException: android.os.BinderProxy.finalize () tiempo de espera después de 10 segundos de errores?

Estamos viendo un número de TimeoutExceptions en GcWatcher.finalize, BinderProxy.finalize y PlainSocketImpl.finalize . 90 +% de ellos ocurren en Android 4.3. Estamos recibiendo informes de este Crittercism de los usuarios en el campo.

Introduzca aquí la descripción de la imagen

El error es una variación de: " com.android.internal.BinderInternal$GcWatcher.finalize() timed out after 10 seconds "

 java.util.concurrent.TimeoutException: android.os.BinderProxy.finalize() timed out after 10 seconds at android.os.BinderProxy.destroy(Native Method) at android.os.BinderProxy.finalize(Binder.java:459) at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:187) at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:170) at java.lang.Thread.run(Thread.java:841) 

Hasta ahora no hemos tenido ninguna suerte reproduciendo el problema en la casa o averiguar lo que podría haber causado.

Cualquier idea que puede causar esto? Cualquier idea de cómo depurar esto y averiguar qué parte de la aplicación provoca esto? Todo lo que arroja luz sobre el tema ayuda.

Más Stacktraces:

 1 android.os.BinderProxy.destroy 2 android.os.BinderProxy.finalize Binder.java, line 482 3 java.lang.Daemons$FinalizerDaemon.doFinalize Daemons.java, line 187 4 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170 5 java.lang.Thread.run Thread.java, line 841 

2

 1 java.lang.Object.wait 2 java.lang.Object.wait Object.java, line 401 3 java.lang.ref.ReferenceQueue.remove ReferenceQueue.java, line 102 4 java.lang.ref.ReferenceQueue.remove ReferenceQueue.java, line 73 5 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170 6 java.lang.Thread.run 

3

 1 java.util.HashMap.newKeyIterator HashMap.java, line 907 2 java.util.HashMap$KeySet.iterator HashMap.java, line 913 3 java.util.HashSet.iterator HashSet.java, line 161 4 java.util.concurrent.ThreadPoolExecutor.interruptIdleWorkers ThreadPoolExecutor.java, line 755 5 java.util.concurrent.ThreadPoolExecutor.interruptIdleWorkers ThreadPoolExecutor.java, line 778 6 java.util.concurrent.ThreadPoolExecutor.shutdown ThreadPoolExecutor.java, line 1357 7 java.util.concurrent.ThreadPoolExecutor.finalize ThreadPoolExecutor.java, line 1443 8 java.lang.Daemons$FinalizerDaemon.doFinalize Daemons.java, line 187 9 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170 10 java.lang.Thread.run 

4

 1 com.android.internal.os.BinderInternal$GcWatcher.finalize BinderInternal.java, line 47 2 java.lang.Daemons$FinalizerDaemon.doFinalize Daemons.java, line 187 3 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170 4 java.lang.Thread.run 

Divulgación completa – Soy el autor de la charla anteriormente mencionada en TLV DroidCon.

Tuve la oportunidad de examinar este problema en muchas aplicaciones de Android, y discutirlo con otros desarrolladores que lo encontraron – y todos llegamos al mismo punto: este problema no se puede evitar, sólo se minimiza.

Eché un vistazo más de cerca a la implementación por defecto del código del recolector de basura de Android, para entender mejor por qué esta excepción es arrojada y sobre cuáles podrían ser las posibles causas. Incluso encontré una posible causa raíz durante la experimentación.

La raíz del problema está en el punto de un dispositivo "Va a dormir" por un tiempo – esto significa que el sistema operativo ha decidido reducir el consumo de la batería mediante la detención de la mayoría de los procesos de tierra de usuario durante un tiempo, , Etc. La forma en que esto se hace – es en un nivel de sistema Linux donde los procesos se interrumpen a mediados de ejecución. Esto puede ocurrir en cualquier momento durante la ejecución normal de la aplicación, pero se detendrá en una llamada de sistema nativo, ya que la conmutación de contexto se realiza en el nivel del kernel. Así que aquí es donde el GC de Dalvik se une a la historia. El código GC de Dalvik (implementado en el proyecto Dalvik en el sitio de AOSP) no es un código complicado. La forma básica de trabajar está cubierta en mis diapositivas DroidCon. Lo que no cubrimos es el bucle GC básico – en el punto donde el colector tiene una lista de objetos para finalizar (y destruir). La lógica de bucle en la base puede simplificarse de esta manera:

  1. Tomar starting_timestamp,
  2. Eliminar el objeto para la lista de objetos a liberar,
  3. Release object – finalize() y llamar a native destroy() si es necesario,
  4. Tomar end_timestamp ,
  5. end_timestamp - starting_timestamp ( end_timestamp - starting_timestamp ) y compare con un valor de tiempo de espera codificado de 10 segundos,
  6. Si el tiempo de espera ha alcanzado – lanzar el concurrent.TimeoutException y matar el proceso.

Ahora considere el siguiente escenario:

La aplicación funciona a lo largo de hacer su cosa. Esto no es una aplicación que se enfrenta al usuario, se ejecuta en segundo plano. Durante esta operación de fondo, los objetos se crean, se usan y se deben recopilar para liberar memoria. Aplicación no se moleste con un Wakelock – ya que esto afectará a la batería adversamente, y parece innecesario. Esto significa que la Aplicación invocará el GC de vez en cuando. Normalmente el GC se ejecuta sin problemas. A veces (muy raramente) el sistema decidirá dormir en medio de la carrera del GC. Esto ocurrirá si ejecuta su aplicación durante un tiempo suficiente y monitorea de cerca los registros de memoria de Dalvik. Ahora, considere la lógica de fecha y hora del bucle GC básico, es posible que el dispositivo inicie la ejecución, tome un start_stamp y vaya a dormir en la llamada nativa destroy() en un objeto del sistema. Cuando se despierta y reanuda la ejecución, el destroy() terminará, y el próximo end_stamp será el tiempo que tomó la llamada destroy() + el tiempo de reposo. Si el tiempo de suspensión fue largo – más de 10 segundos, se emitirá la excepción concurrent.timeout.

He visto esto en los gráficos generados a partir de la secuencia de comandos de análisis python – para aplicaciones de sistema de Android, no sólo mis propias aplicaciones supervisadas. Recoger suficientes registros, que finalmente verá.

Línea de fondo:

No se puede evitar el problema; se encontrará si la aplicación se ejecuta en segundo plano. Puede mitigar tomando un wakelock, y evitar que el dispositivo de dormir, pero que es una historia diferente en conjunto, y un nuevo dolor de cabeza, y tal vez otra charla en otro con.

Puede minimizar el problema al reducir las llamadas GC, lo que hace que el escenario sea menos probable. Consejos están en las diapositivas.

Todavía no he tenido la oportunidad de repasar el código GC de Dalvik 2 (aka ART), que cuenta con una nueva característica de Compactación Generacional, o realizó cualquier experimento con Android Lollipop.

Añadido 7/5/2015:

Después de revisar la agregación de informes de Crash para este tipo de bloqueo, parece que estos bloqueos de la versión 5.0+ de Android OS (Lollipop con ART) sólo representan el 0,5% de este tipo de fallo. Esto significa que el ART GC cambios ha reducido la frecuencia de estos accidentes.

Añadido 6/1/2016:

Parece que el proyecto de Android ha añadido una gran cantidad de información sobre cómo funciona el GC en Dalvik 2.0 (aka ART). Puedes leer sobre esto aquí – Depuración de colección de basura de ART . También analiza algunas herramientas para obtener información sobre el comportamiento del GC para su aplicación. Enviar un SIGQUIT al proceso de la aplicación causará esencialmente una ANR y volcará el estado de la aplicación a un archivo de registro para su análisis.

Lo vemos constantemente, en toda nuestra aplicación, usando Crashlytics. El accidente suele suceder en el código de la plataforma. Un pequeño muestreo:

Android.database.CursorWindow.finalize () se ha agotado después de 10 segundos

Java.util.regex.Matcher.finalize () ha caducado después de 10 segundos

Android.graphics.Bitmap $ BitmapFinalizer.finalize () se ha agotado después de 10 segundos

Org.apache.http.impl.conn.SingleClientConnManager.finalize () se ha agotado después de 10 segundos

Java.util.concurrent.ThreadPoolExecutor.finalize () se ha agotado después de 10 segundos

Android.os.BinderProxy.finalize () se agotó después de 10 segundos

Android.graphics.Path.finalize () se ha agotado después de 10 segundos

Los dispositivos en los que esto sucede son abrumadoramente (pero no exclusivamente) dispositivos fabricados por Samsung. Eso podría significar que la mayoría de nuestros usuarios están usando dispositivos Samsung; Alternativamente podría indicar un problema con los dispositivos Samsung. No estoy realmente seguro.

Supongo que esto realmente no responde a sus preguntas, pero sólo quería reforzar que esto parece bastante común, y no es específico para su aplicación.

He encontrado algunas diapositivas sobre este tema.

http://de.slideshare.net/DroidConTLV/android-crash-analysis-and-the-dalvik-garbage-collector-tools-and-tips

En estas diapositivas el autor dice que parece ser un problema con GC, si hay un montón de objetos o objetos enormes en montón. La diapositiva también incluye una referencia a una aplicación de ejemplo y una secuencia de comandos python para analizar este problema.

https://github.com/oba2cat3/GCTest

https://github.com/oba2cat3/logcat2memorygraph

Además, encontré una pista en el comentario # 3 de este lado: https://code.google.com/p/android/issues/detail?id=53418#c3

Tiempo de espera de los receptores de difusión después de 10 segundos. Posiblemente su hacer una llamada asincrónica (incorrecta) de un receptor de la difusión y 4.3 lo detecta realmente.

Una cosa que es invariablemente cierto es que en este momento, el dispositivo sería sofocante para una cierta memoria (que es generalmente la razón de la GC a lo más probable consigue accionada).

Como se mencionó anteriormente por casi todos los autores, este problema surge cuando Android intenta ejecutar GC mientras la aplicación está en segundo plano. En la mayoría de los casos donde lo observamos, el usuario hizo una pausa en la aplicación bloqueando su pantalla. Esto también podría indicar una pérdida de memoria en algún lugar de la aplicación o el dispositivo que ya está cargado. Así que la única manera legítima de minimizarlo es:

  • Para asegurar que no hay fugas de memoria, y
  • Para reducir la huella de memoria de la aplicación en general.

El finalizeQueue puede ser demasiado largo

Creo que java puede requerir GC.SuppressFinalize () & GC.ReRegisterForFinalize () para permitir al usuario reducir la longitud finalizedQueue explícitamente

Si el código fuente de JVM está disponible, puede implementar este método nosotros mismos, como el fabricante de ROM de Android

 try { Class<?> c = Class.forName("java.lang.Daemons"); Field maxField = c.getDeclaredField("MAX_FINALIZE_NANOS"); maxField.setAccessible(true); maxField.set(null, Long.MAX_VALUE); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } 
  • Tratando de guardar la imagen en una carpeta de imágenes determinada que no se ha creado
  • Pasar objetos activos entre servicios a través de AIDL
  • ¿Cómo escuchar dev / binder?
  • Acceso a Unity StreamingAssets en Android
  • ¿Existe alguna convención para el almacenamiento de tarjetas SD de Android?
  • Descriptor de archivos compartidos con la carpeta de Android
  • No se reconoce la carpeta de Google Drive al descargarla en la aplicación de Android
  • No tiene ningún directorio de librerías en Android Studio
  • Diferencias entre / sdcard / emulated / 0 y / sdcard
  • Rápida eliminación de la carpeta con más de 30000 imágenes en Android
  • Renombrar carpeta en la tarjeta SD
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.