Google 致力于为黑人社区推动种族平等。查看具体举措
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Miglioramenti di Android 8.0 ART

Il runtime Android (ART) è stato notevolmente migliorato nella versione Android 8.0. L'elenco seguente riassume i miglioramenti che i produttori di dispositivi possono aspettarsi in ART.

Garbage collector di compattazione simultanea

Come annunciato al Google I / O, ART presenta un nuovo Garbage Collector (GC) a compattazione simultanea in Android 8.0. Questo raccoglitore compatta l'heap ogni volta che viene eseguito GC e mentre l'app è in esecuzione, con una sola breve pausa per l'elaborazione delle radici dei thread. Ecco i suoi vantaggi:

  • GC compatta sempre l'heap: dimensioni dell'heap inferiori del 32% in media rispetto ad Android 7.0.
  • La compattazione consente l'allocazione degli oggetti del puntatore di urto locale del thread: le allocazioni sono più veloci del 70% rispetto ad Android 7.0.
  • Offre tempi di pausa inferiori dell'85% per il benchmark H2 rispetto ad Android 7.0 GC.
  • I tempi di pausa non vengono più scalati con la dimensione dell'heap; le app dovrebbero essere in grado di utilizzare grossi cumuli senza doversi preoccupare del jank.
  • Dettagli sull'implementazione GC - Barriere di lettura:
    • Le barriere di lettura sono una piccola quantità di lavoro svolto per ogni campo oggetto letto.
    • Questi sono ottimizzati nel compilatore, ma potrebbero rallentare alcuni casi d'uso.

Ottimizzazioni del ciclo

Una vasta gamma di ottimizzazioni del ciclo è impiegata da ART nella versione Android 8.0:

  • I limiti controllano le eliminazioni
    • Statico: è stato dimostrato che gli intervalli rientrano nei limiti in fase di compilazione
    • Dinamico: i test di runtime assicurano che i loop rimangano entro i limiti (altrimenti disattivati)
  • Eliminazioni variabili di induzione
    • Rimuovere l'induzione morta
    • Sostituisci l'induzione che viene utilizzata solo dopo il ciclo con espressioni in forma chiusa
  • Eliminazione del codice morto all'interno del loop-body, rimozione di interi loop che diventano morti
  • Riduzione della forza
  • Trasformazioni ad anello: inversione, interscambio, scissione, srotolamento, unimodulare, ecc.
  • SIMDizzazione (chiamata anche vettorizzazione)

L'ottimizzatore di loop risiede nel proprio passaggio di ottimizzazione nel compilatore ART. La maggior parte delle ottimizzazioni del ciclo sono simili alle ottimizzazioni e alla semplificazione altrove. Le sfide sorgono con alcune ottimizzazioni che riscrivono il CFG in un modo più elaborato del solito, perché la maggior parte delle utilità CFG (vedi nodes.h) si concentra sulla creazione di un CFG, non sulla riscrittura.

Analisi della gerarchia delle classi

ART in Android 8.0 utilizza Class Hierarchy Analysis (CHA), un'ottimizzazione del compilatore che devirtualizza le chiamate virtuali in chiamate dirette in base alle informazioni generate dall'analisi delle gerarchie di classi. Le chiamate virtuali sono costose poiché vengono implementate attorno a una ricerca vtable e richiedono un paio di carichi dipendenti. Inoltre, le chiamate virtuali non possono essere inline.

Di seguito è riportato un riepilogo dei miglioramenti correlati:

  • Aggiornamento dinamico dello stato del metodo di implementazione singola - Alla fine del tempo di collegamento della classe, quando vtable è stato popolato, ART esegue un confronto entry-by-entry con il vtable della super classe.
  • Ottimizzazione del compilatore: il compilatore trarrà vantaggio dalle informazioni sull'implementazione singola di un metodo. Se un metodo A.foo ha un flag di implementazione singola, il compilatore devirtualizzerà la chiamata virtuale in una chiamata diretta e, di conseguenza, tenterà ulteriormente di inline la chiamata diretta.
  • Invalidazione del codice compilato: anche alla fine del tempo di collegamento della classe quando le informazioni sull'implementazione singola vengono aggiornate, se il metodo A.foo che in precedenza aveva un'implementazione singola ma quello stato è ora invalidato, tutto il codice compilato dipende dal presupposto che il metodo A. foo ha bisogno di una singola implementazione per invalidare il codice compilato.
  • Deottimizzazione: per il codice compilato live che è in pila, verrà avviata la deottimizzazione per forzare il codice compilato invalidato in modalità interprete per garantire la correttezza. Verrà utilizzato un nuovo meccanismo di deottimizzazione che è un ibrido di deottimizzazione sincrona e asincrona.

Cache in linea nei file .oat

ART ora utilizza cache in linea e ottimizza i siti di chiamata per i quali esistono dati sufficienti. La funzione cache inline registra ulteriori informazioni di runtime nei profili e le utilizza per aggiungere ottimizzazioni dinamiche alla compilazione anticipata.

Dexlayout

Dexlayout è una libreria introdotta in Android 8.0 per analizzare i file dex e riordinarli secondo un profilo. Dexlayout mira a utilizzare le informazioni di profilazione di runtime per riordinare le sezioni del file dex durante la compilazione della manutenzione inattiva sul dispositivo. Raggruppando le parti del file dex a cui spesso si accede insieme, i programmi possono avere migliori schemi di accesso alla memoria da località migliorate, risparmiando RAM e abbreviando i tempi di avvio.

Poiché le informazioni sul profilo sono attualmente disponibili solo dopo che le app sono state eseguite, dexlayout è integrato nella compilazione sul dispositivo di dex2oat durante la manutenzione inattiva.

Rimozione della cache Dex

Fino ad Android 7.0, l'oggetto DexCache possedeva quattro grandi array, proporzionali al numero di determinati elementi nel DexFile, ovvero:

  • stringhe (un riferimento per DexFile :: StringId),
  • tipi (un riferimento per DexFile :: TypeId),
  • metodi (un puntatore nativo per DexFile :: MethodId),
  • campi (un puntatore nativo per DexFile :: FieldId).

Questi array sono stati utilizzati per il recupero rapido di oggetti che abbiamo risolto in precedenza. In Android 8.0, tutti gli array sono stati rimossi tranne l'array dei metodi.

Prestazioni di interprete

Le prestazioni dell'interprete sono notevolmente migliorate nella versione Android 7.0 con l'introduzione di "mterp", un interprete dotato di un meccanismo di recupero / decodifica / interpretazione di base scritto in linguaggio assembly. Mterp è modellato sul veloce interprete Dalvik e supporta arm, arm64, x86, x86_64, mips e mips64. Per il codice computazionale, l'mterp di Art è più o meno paragonabile all'interprete veloce di Dalvik. Tuttavia, in alcune situazioni può essere significativamente, e anche drammaticamente, più lento:

  1. Invoca prestazioni.
  2. Manipolazione di stringhe e altri utenti pesanti di metodi riconosciuti come intrinseci in Dalvik.
  3. Maggiore utilizzo della memoria dello stack.

Android 8.0 risolve questi problemi.

Più inlining

A partire da Android 6.0, ART può incorporare qualsiasi chiamata all'interno degli stessi file dex, ma può solo incorporare metodi foglia da diversi file dex. C'erano due ragioni per questa limitazione:

  1. L'inlining da un altro file dex richiede l'utilizzo della cache dex di quell'altro file dex, a differenza dell'inlining dello stesso file dex, che potrebbe semplicemente riutilizzare la cache dex del chiamante. La cache dex è necessaria nel codice compilato per un paio di istruzioni come chiamate statiche, caricamento di stringhe o caricamento di classi.
  2. Le mappe dello stack codificano solo un indice del metodo all'interno del file dex corrente.

Per affrontare queste limitazioni, Android 8.0:

  1. Rimuove l'accesso alla cache dex dal codice compilato (vedere anche la sezione "Rimozione della cache Dex")
  2. Estende la codifica della mappa dello stack.

Miglioramenti alla sincronizzazione

Il team ART ha messo a punto i percorsi del codice MonitorEnter / MonitorExit e ha ridotto la nostra dipendenza dalle tradizionali barriere di memoria su ARMv8, sostituendole con nuove istruzioni (acquisizione / rilascio) ove possibile.

Metodi nativi più veloci

Chiamate native più veloci a Java Native Interface (JNI) sono disponibili utilizzando le annotazioni @FastNative e @CriticalNative . Queste ottimizzazioni di runtime ART integrate velocizzano le transizioni JNI e sostituiscono la notazione JNI! Bang ormai deprecata. Le annotazioni non hanno effetto sui metodi non nativi e sono disponibili solo per il codice del linguaggio Java della piattaforma sul bootclasspath (nessun aggiornamento del Play Store).

L'annotazione @FastNative supporta metodi non statici. Utilizzare questo se un metodo accede a un jobject come parametro o valore di ritorno.

L'annotazione @CriticalNative fornisce un modo ancora più veloce per eseguire metodi nativi, con le seguenti limitazioni:

  • I metodi devono essere statici: nessun oggetto per parametri, valori restituiti o un valore this implicito.
  • Solo i tipi primitivi vengono passati al metodo nativo.
  • Il metodo nativo non utilizza i parametri JNIEnv e jclass nella definizione della funzione.
  • Il metodo deve essere registrato con RegisterNatives invece di fare affidamento sul collegamento JNI dinamico.

@FastNative può migliorare le prestazioni del metodo nativo fino a 3 volte e @CriticalNative fino a 5 volte. Ad esempio, una transizione JNI misurata su un dispositivo Nexus 6P:

Richiamo JNI (Java Native Interface) Tempo di esecuzione (in nanosecondi)
JNI regolare 115
! bang JNI 60
@FastNative 35
@CriticalNative 25