Il runtime Android (ART) è il runtime predefinito per i dispositivi che eseguono Android 5.0 (livello API 21) e versioni successive. Questo runtime offre una serie di funzionalità che migliorano le prestazioni e la fluidità della piattaforma e delle app Android. Puoi trovare ulteriori informazioni sulle nuove funzionalità di ART nella sezione Introduzione ARTE.
Tuttavia, alcune tecniche che funzionano su Dalvik non funzionano su ART. Questo di questo documento consente di sapere cosa occorre tenere presente quando si esegue la migrazione di un compatibile con ART. La maggior parte delle app dovrebbe funzionare solo con ART.
Risolvere i problemi di garbage collection (GC)
In Dalvik, le app spesso trovano utile chiamare in modo esplicito
System.gc()
per richiedere la garbage collection (GC). Dovrebbe essere
molto meno necessario con ART, in particolare se si richiama la garbage collection
per impedire le app di tipo GC_FOR_ALLOC
o per ridurre la frammentazione. Puoi verificare quale runtime è in uso
chiamando il numero System.getProperty("java.vm.version")
. Se ART è in uso, il valore della proprietà
è "2.0.0"
o superiore.
ART utilizza il raccoglitore di copia contemporanea (CC) che compatta contemporaneamente l'heap Java. Per questo motivo, evita di usare tecniche incompatibili con la compattazione di GC (come il salvataggio dei cursori dell'istanza di servizio). Questo è particolarmente importante per le app che utilizzano JNI (Java Native Interface). Per ulteriori informazioni, consulta l'articolo sulla prevenzione dei problemi JNI.
Prevenire i problemi di JNI
Il JNI di ART è un po' più severo di quello di Dalvik. È un'idea particolarmente buona per usare la modalità CheckJNI per rilevare problemi comuni. Se la tua app utilizza C/C++ consulta il seguente articolo:
Debug Android JNI con CheckJNI
Controllo del codice JNI per problemi di garbage collection
Il raccoglitore per la copia simultanea (CC) potrebbe spostare gli oggetti in memoria per la compattazione. Se utilizzi il codice C/C++, eseguire operazioni incompatibili con la compattazione di GC. Abbiamo migliorato ControllaJNI per identificare alcuni potenziali problemi (come descritto in JNI modifiche nei riferimenti locali in ICS).
Un aspetto da considerare in particolare è l'uso
Get...ArrayElements()
e Release...ArrayElements()
funzioni. Nei runtime con GC non compatta,
Le funzioni Get...ArrayElements()
in genere restituiscono un riferimento alla
effettiva a supporto dell'oggetto array. Se apporti una modifica a una delle
restituiti elementi array, l'oggetto array è a sua volta modificato (e gli argomenti
a Release...ArrayElements()
vengono generalmente ignorati). Tuttavia, se
la compattazione di GC è in uso, le funzioni Get...ArrayElements()
potrebbero
e restituire una copia della memoria. Se si usa il riferimento in modo improprio durante la compattazione di GC
durante l'uso, questo può causare il danneggiamento della memoria o altri problemi. Ad esempio:
- Se apporti modifiche agli elementi array restituiti, devi richiamare il metodo
la funzione
Release...ArrayElements()
appropriata quando hai finito, per assicurarti che le modifiche apportate vengano copiate correttamente . - Quando rilasci gli elementi array di memoria, devi utilizzare la classe
in base alle modifiche apportate:
- Se non hai apportato modifiche agli elementi dell'array, utilizza
Modalità
JNI_ABORT
, che rilascia la memoria senza copiare all'oggetto array sottostante. - Se hai apportato modifiche all'array e non è necessario il riferimento
utilizza il codice
0
(che aggiorna l'oggetto array e libera la copia della memoria). - Se hai apportato modifiche all'array di cui vuoi eseguire il commit e vuoi
per conservare la copia dell'array, utilizza
JNI_COMMIT
(che si aggiorna l'oggetto array sottostante e conserva la copia).
- Se non hai apportato modifiche agli elementi dell'array, utilizza
Modalità
- Quando chiami
Release...ArrayElements()
, restituisci lo stesso che è stato originariamente restituito daGet...ArrayElements()
. Per Ad esempio, non è sicuro incrementare il puntatore originale (per eseguire la scansione restituiti elementi dell'array), quindi passa il puntatore incrementatoRelease...ArrayElements()
. Il superamento di questo puntatore modificato può causare la memoria sbagliata da liberare, con un conseguente danneggiamento della memoria.
Gestione degli errori
JNI di ART genera errori in diversi casi in cui Dalvik non lo fa. (Una volta puoi rilevare molti casi di questo tipo eseguendo test con CheckJNI.)
Ad esempio, se RegisterNatives
viene chiamato con un metodo che
non esiste (forse perché il metodo è stato rimosso da uno strumento come
ProGuard), ART ora genera correttamente NoSuchMethodError
:
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 registra anche un errore (visibile in logcat) se RegisterNatives
è
chiamata senza alcun metodo:
W/art ( 1234): JNI RegisterNativeMethods: attempt to register 0 native methods for <classname>
Inoltre, JNI funziona GetFieldID()
e
GetStaticFieldID()
ora lancia correttamente NoSuchFieldError
anziché restituire semplicemente null. Analogamente, GetMethodID()
e
GetStaticMethodID()
ora lancia correttamente NoSuchMethodError
.
Ciò può causare errori CheckJNI a causa di eccezioni non gestite o del
per i chiamanti Java del codice nativo. Ciò rende
particolarmente importante per testare le app compatibili con ART con la modalità CheckJNI.
ART si aspetta che gli utenti utilizzino i metodi CallNonvirtual...Method()
di JNI
(ad esempio CallNonvirtualVoidMethod()
) per utilizzare la dichiarazione del metodo
non è una sottoclasse, come richiesto dalla specifica JNI.
Prevenire i problemi relativi alle dimensioni dello stack
Dalvik aveva stack separati per il codice nativo e Java, con un'architettura Java predefinita
una dimensione dello stack di 32 kB e uno stack nativo predefinito di 1 MB. ART ha un obiettivo
per una località migliore. Solitamente, lo stack Thread
ART
dovrebbe essere più o meno uguale a quella di Dalvik. Tuttavia, se specifichi esplicitamente
e impostare le dimensioni dello stack, potresti dover rivedere questi valori per le app in esecuzione
ART.
- In Java, rivedi le chiamate al costruttore
Thread
che specificano uno stack esplicito dimensioni. Ad esempio, dovrai aumentare le dimensioni se si verifica ilStackOverflowError
. - In C/C++, esamina l'utilizzo di
pthread_attr_setstack()
epthread_attr_setstacksize()
per i thread che eseguono anche il codice Java tramite JNI. Ecco un esempio di errore registrato quando un'app tenta di chiamare JNIAttachCurrentThread()
quando la dimensione del thread p è troppo piccola:F/art: art/runtime/thread.cc:435] Attempt to attach a thread with a too-small stack (16384 bytes)
Modifiche al modello a oggetti
Dalvik ha consentito erroneamente alle sottoclassi di sostituire i metodi privati del pacchetto. ART genera un avviso nei seguenti casi:
Before Android 4.1, method void com.foo.Bar.quux() would have incorrectly overridden the package-private method in com.quux.Quux
Se intendi eseguire l'override del metodo di una classe in un pacchetto diverso, dichiara la
come public
o protected
.
Ora Object
ha campi privati. App che si riflettono sui campi
nelle loro gerarchie di classi, dobbiamo fare attenzione a non cercare di esaminare
campi di Object
. Ad esempio, se stai ripetendo un corso
la gerarchia come parte di un framework di serializzazione,
Class.getSuperclass() == java.lang.Object.class
anziché continuare finché il metodo non restituisce null
.
Il proxy InvocationHandler.invoke()
ora riceve null
se non sono presenti
anziché un array vuoto. Questo comportamento è stato documentato in precedenza, ma
non vengono gestite correttamente in Dalvik. Le versioni precedenti di Mockito hanno difficoltà con
questo, quindi utilizza una versione Mockito aggiornata durante il test con ART.
Risoluzione dei problemi di compilazione AOT
La compilazione Java Ahead-Of-Time (AOT) di ART dovrebbe funzionare per tutte le applicazioni Java standard
le API nel tuo codice. Compilation eseguita da ART
Strumento dex2oat
; in caso di problemi relativi
dex2oat
al momento dell'installazione, comunicacelo (consulta la sezione Segnalazione di problemi) per consentirci di risolverli il più rapidamente possibile.
il più possibile. Alcuni aspetti da sottolineare:
- Al momento dell'installazione, ART esegue una verifica bytecode più rigorosa rispetto a Dalvik. Il codice prodotto dagli strumenti di compilazione di Android dovrebbe essere sufficiente. Tuttavia, alcune strumenti di post-elaborazione (soprattutto gli strumenti che eseguono l'offuscamento) possono generare file non validi che sono tollerati da Dalvik ma rifiutati da ART. Siamo stati collaborare con i fornitori di strumenti per individuare e risolvere questi problemi. In molti casi, ottenere le versioni più recenti degli strumenti e la rigenerazione dei file DEX può per risolvere problemi di produzione e facilità d'uso.
- Ecco alcuni problemi tipici segnalati dallo strumento di verifica ART:
- flusso di controllo non valido
- sbilanciato:
monitorenter
/monitorexit
- Dimensioni elenco dei tipi di parametri di lunghezza 0
- Alcune app hanno dipendenze nel file
.odex
installato formato in/system/framework
,/data/dalvik-cache
o nella directory di output ottimizzata diDexClassLoader
. Questi ora sono file ELF e non una forma estesa di file DEX. Mentre ART prova seguire le stesse regole di denominazione e blocco di Dalvik, le app non sul formato file; il formato è soggetto a modifiche senza preavviso.Nota: in Android 8.0 (livello API 26) e superiore, la directory di output ottimizzata per
DexClassLoader
è stata ritirata. Per ulteriori informazioni, consulta la documentazione relativaDexClassLoader()
come costruttore.
Problemi relativi ai report
Se riscontri problemi non dovuti a problemi relativi a JNI dell'app, segnala
tramite lo strumento Android Open Source Issue Tracker all'indirizzo https://code.google.com/p/android/issues/list.
Includi un "adb bugreport"
e un link all'app nella sezione
Play Store, se disponibile. Altrimenti, se possibile, allega un APK che riproduca
risolvere il problema. Tieni presente che i problemi (inclusi gli allegati) sono visibili pubblicamente
visibile.