Android Runtime (ART) es el entorno de ejecución predeterminado para dispositivos que ejecutan Android 5.0 (nivel de API 21) y versiones posteriores Este entorno de ejecución ofrece varias funciones que mejoran el rendimiento y la fluidez de la plataforma y las apps de Android. Encuentra más información sobre las nuevas funciones de ART en Introducción ARTE
Sin embargo, algunas técnicas que funcionan en Dalvik no sirven en ART. Esta te permite saber qué aspectos hay que tener en cuenta al migrar un archivo para que sea compatible con ART. La mayoría de las apps solo deberían funcionar cuando se ejecutan con ART.
Cómo afrontar problemas de recolección de elementos no utilizados (GC)
Con Dalvik, en las apps, a menudo, resulta útil llamar de manera explícita
System.gc()
para solicitar la recolección de elementos no utilizados (GC) Debe ser
mucho menos necesaria con ART, en especial si invocas la recolección de elementos no utilizados
para evitar el tipo GC_FOR_ALLOC
o reducir la fragmentación. Puedes verificar qué entorno de ejecución está en uso
llamando a System.getProperty("java.vm.version")
. Si ART está en uso, el valor de la propiedad
es "2.0.0"
o superior.
ART usa un recopilador de copia simultánea (CC), que compacta el montón de Java al mismo tiempo. Debido a esto, debes evitar el uso de técnicas incompatibles con la compactación de recolección de elementos no utilizados (como guardar punteros en el objeto datos de la instancia). Esto es particularmente importante para las aplicaciones que usan el Interfaz nativa de Java (JNI). Para obtener más información, consulta Cómo evitar problemas de la JNI.
Prevención de problemas de la JNI
La JNI del ART es un poco más estricta que la de Dalvik. Es especialmente una buena idea usar el modo CheckJNI para detectar problemas comunes. Si tu app usa C/C++ código, debes consultar el siguiente artículo:
Depuración JNI de Android con CheckJNI
Verificación del código de la JNI en busca de problemas de recolección de elementos no utilizados
El colector de Copia simultánea (CC) puede mover objetos en la memoria para la compactación. Si usas código C/C++, no realizar operaciones que son incompatibles con el recolector con compactación de elementos no utilizados. Mejoramos CheckJNI para identificar algunos problemas potenciales (como se describe en JNI Cambios de referencias locales en ICS).
Un área que debe observarse en particular es el uso de
Get...ArrayElements()
y Release...ArrayElements()
funciones. En entornos de ejecución con recolección sin compactar, el
Las funciones Get...ArrayElements()
suelen mostrar una referencia al
la memoria real que respalda el objeto del array. Si realizas un cambio en uno de los
los elementos de array que se devuelven, el objeto de array se cambia a sí mismo (y los argumentos
a Release...ArrayElements()
se suelen ignorar). Sin embargo, si
se está usando la recolección con compactación de elementos no utilizados, las funciones Get...ArrayElements()
pueden
devuelve una copia del recuerdo. Si haces un uso inadecuado de la referencia cuando se compacta el recolector con compactación de elementos no utilizados,
en uso, puede dañar la memoria u otros problemas. Por ejemplo:
- Si realizas algún cambio en los elementos del array que se devuelven, debes llamar al
la función
Release...ArrayElements()
adecuada cuando hayas terminado, para asegurarte de que los cambios que hiciste se copien correctamente en la base de datos Array. - Cuando lanzas los elementos del array de memoria, debes usar los
según los cambios que hayas realizado:
- Si no realizaste ningún cambio en los elementos del array, usa
Modo
JNI_ABORT
, que libera la memoria sin copiar cambia de vuelta al objeto de array subyacente. - Si realizaste cambios en el array y no necesitas la referencia
más, usa el código
0
(que actualiza el objeto del array y libera la copia del recuerdo). - Si modificaste el array que quieres confirmar y quieres
Para mantener la copia del array, usa
JNI_COMMIT
(que actualiza el objeto de array subyacente y retiene la copia).
- Si no realizaste ningún cambio en los elementos del array, usa
Modo
- Cuando llames a
Release...ArrayElements()
, se mostrará el mismo que mostró originalmenteGet...ArrayElements()
. Para ejemplo, no es seguro aumentar el puntero original (para buscar los elementos de array que se muestran) y, luego, pasa el puntero incrementado aRelease...ArrayElements()
Pasar este puntero modificado puede causar la memoria incorrecta para liberarse, lo que genera daños en la memoria.
Manejo de errores
La JNI del ART genera errores en varios casos en los que Dalvik no lo hace. (Una vez De nuevo, puedes detectar muchos casos realizando pruebas con CheckJNI).
Por ejemplo, si se llama a RegisterNatives
con un método que
no existe (quizás porque el método fue eliminado por una herramienta como
ProGuard), ART ahora arroja NoSuchMethodError
correctamente:
08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main 08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError: no static or non-static method "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I" 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.Runtime.nativeLoad(Native Method) 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.Runtime.doLoad(Runtime.java:421) 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.Runtime.loadLibrary(Runtime.java:362) 08-12 17:09:41.082 13823 13823 E AndroidRuntime: at java.lang.System.loadLibrary(System.java:526)
ART también registra un error (visible en logcat) si RegisterNatives
es
llamada sin métodos:
W/art ( 1234): JNI RegisterNativeMethods: attempt to register 0 native methods for <classname>
Además, las funciones JNI GetFieldID()
y
GetStaticFieldID()
ahora arroja NoSuchFieldError
correctamente.
en lugar de mostrar un valor nulo. De manera similar, GetMethodID()
y
GetStaticMethodID()
ahora arroja NoSuchMethodError
correctamente
Esto puede provocar fallas en CheckJNI debido a las excepciones no controladas o la
excepciones que se arrojan a los emisores de Java de código nativo. Esto hace que
es particularmente importante probar apps compatibles con el ART a través del modo CheckJNI.
ART espera usuarios de los métodos CallNonvirtual...Method()
de JNI
(como CallNonvirtualVoidMethod()
) para usar el método
no una subclase, como lo exige la especificación de JNI.
Prevención de problemas de tamaño de pila
Dalvik tenía pilas separadas para el código nativo y el código Java con un código Java predeterminado
tamaño de pila de 32 KB y un tamaño de pila nativa predeterminado de 1 MB. ART tiene una aplicación
para una mejor localidad. Por lo general, la pila Thread
de ART
el tamaño debería ser aproximadamente el mismo que para Dalvik. Sin embargo, si explícitamente
y configurar tamaños de pila, quizás debas revisar esos valores para las apps que se ejecutan en
ART.
- En Java, revisa las llamadas al constructor
Thread
que especifican una pila explícita de tamaño del ensamble. Por ejemplo, deberás aumentar el tamaño si se produceStackOverflowError
. - En C/C++, revisa el uso de
pthread_attr_setstack()
ypthread_attr_setstacksize()
para subprocesos que también ejecutan código Java mediante JNI A continuación, se muestra un ejemplo del error que se registra cuando una app intenta llamar a JNIAttachCurrentThread()
cuando el tamaño de pthread es demasiado pequeño:F/art: art/runtime/thread.cc:435] Attempt to attach a thread with a too-small stack (16384 bytes)
Cambios de modelo de objeto
Dalvik permitió de modo incorrecto que las subclases anulen los métodos privados de paquetes. El ART emite una precaución en dichos casos:
Before Android 4.1, method void com.foo.Bar.quux() would have incorrectly overridden the package-private method in com.quux.Quux
Si quieres anular un método de una clase en un paquete diferente, declara la
método como public
o protected
.
Object
ahora tiene campos privados. Apps sobre campos
en las jerarquías de sus clases, deben tener cuidado de no observar las
campos de Object
. Por ejemplo, si realizas una iteración en una clase
de Terraform como parte de un framework de serialización,
Class.getSuperclass() == java.lang.Object.class
en lugar de continuar hasta que el método muestre null
.
El proxy InvocationHandler.invoke()
ahora recibe null
si no hay
en lugar de un array vacío. Este comportamiento se documentó anteriormente, pero
no se maneja de forma correcta en Dalvik. Las versiones anteriores de Mockito tienen dificultades con lo siguiente:
así que usa una versión actualizada de Mockito cuando realices pruebas con el ART.
Solución de problemas de compilación de AOT
La compilación de Java por adelantado (AOT) de ART debería funcionar con todas las versiones estándar de Java.
código. La compilación es interpretada por ART's
Herramienta dex2oat
; si tienes algún problema relacionado con
dex2oat
en el momento de la instalación, avísanos (consulta Cómo informar problemas) para que podamos solucionarlos lo antes posible
de la forma más eficaz posible. Algunos problemas que deben tenerse en cuenta:
- Durante la instalación, el ART realiza una verificación de código de bytes más estricta que la de Dalvik. El código que producen las herramientas de compilación de Android debe funcionar bien. Sin embargo, algunos las herramientas de procesamiento posterior (especialmente las que realizan ofuscación) pueden producir archivos no válidos que Dalvik tolera y ART rechaza. Hemos estado trabajar con proveedores de herramientas para encontrar y solucionar esos problemas. En muchos casos, obtener las versiones más recientes de tus herramientas y la regeneración de los archivos DEX puede solucionar estos problemas problemas.
- Estos son algunos de los problemas típicos que marca el verificador del ART:
- flujo de control no válido
- desequilibrado
monitorenter
/monitorexit
- tamaño de lista del tipo de parámetro de longitud 0
- Algunas apps tienen dependencias en el archivo
.odex
instalado en/system/framework
,/data/dalvik-cache
o en el directorio de salida optimizado deDexClassLoader
. Estos ahora son archivos ELF y no formas extendidas de archivos DEX. Mientras ART intenta las mismas reglas de nomenclatura y bloqueo de Dalvik, las apps no deberían en el formato de archivo; el formato está sujeto a cambios sin previo aviso.Nota: En Android 8.0 (nivel de API 26) y superior, el directorio de salida optimizado
DexClassLoader
quedó obsoleto. Para obtener más información, consulta la documentación delDexClassLoader()
.
Cómo informar problemas
Si tienes algún problema que no se deba a problemas de JNI de la app, infórmalo
a través de la Herramienta de seguimiento de errores del Proyecto de código abierto de Android en https://code.google.com/p/android/issues/list.
Incluye un "adb bugreport"
y un vínculo a la app en la app de Google
Play Store (si está disponible). De lo contrario, si es posible, adjunta un APK que se reproduzca
el problema. Ten en cuenta que los problemas (incluidos los archivos adjuntos) se
sean visibles.