Elaborato De Gregorio Pierluigi N46-001365
Transcript
Elaborato De Gregorio Pierluigi N46-001365
Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Sistemi Operativi Studio degli Android Runtime Environments ART e Dalvik Anno Accademico 2014/2015 Candidato: Pierluigi De Gregorio matr. N46/1365 Dedico questo elaborato ai miei genitori, mia forza economica e morale, e alla mia ragazza che mi ha sempre sostenuto e ha sempre creduto in me. Grazie a loro ho sempre trovato la forza di rialzarmi ad ogni caduta e combattere ogni ostacolo. Indice Introduzione iv 1 Dalvik Virtual Machine 1 1.1 Un’architettura basata su registri . . . . . . . . . . . . . . . . . . . . . . 1 1.2 File .DEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 Layout del file .DEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4 File ODEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.5 Differenze con la JVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.6 Compilatore JIT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.7 Zygote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.8 Garbage Collector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2 Android Runtime (ART) 15 2.1 Miglioramenti apportati . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.2 DEX2OAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.3 Struttura del file .ELF . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.4 Compilazione Ahead-Of-Time (AOT) . . . . . . . . . . . . . . . . . . . . 20 2.5 Garbage Collector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Conclusioni 25 Bibliografia 26 ii Elenco delle figure 1 Architettura Android OS . . . . . . . . . . . . . . . . . . . . . . . . . . v 1.1 Confronto tra JVM e DVM . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Struttura di un file .jar(sinistra) e di un file .dex(destra) . . . . . . . . . 4 1.3 Snellimento del file .jar . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4 Processo Zygote . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.1 Confronto tra la conversione in Android Dalvik e ART . . . . . . . . . . 17 2.2 file .ELF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.3 Processo di compilazione in ART . . . . . . . . . . . . . . . . . . . . . . 20 iii Introduzione Il 5 novembre 2007 si affacciò per la prima volta sul mondo dei dispositivi mobile Android OS, il sistema operativo più utilizzato, ad oggi, dalle aziende produttrici di smartphone e smartwatch. Basato su kernel Linux, Android OS è un sistema operativo Open Source che utilizza software basati su diverse licenze, tra le quali la Licenza Apache grazie alla quale Google, azienda proprietaria di questo OS, può rilasciare liberamente distribuzioni e modifiche del codice sorgente[1]. A tal proposito, infatti, Google ha dato vita al cosiddetto Android Open Source Project (AOSP), che ha lo scopo principale di ”migliorare l’esperienza mobile per gli utenti” e garantire che i dispositivi mobili ”siano più consapevoli della posizione e delle preferenze del loro proprietario”[2]. In questo modo il colosso di Mountain View è riuscito ad ottenere due grandi risultati: da un lato ha dato vita ad una grande comunità di sviluppatori che ogni giorno supportano e danno vita ad applicazioni che migliorano sensibilmente le funzionalità dei dispositivi, dall’altro si è assicurata una vasta compatibilità di dispositivi mobile mettendo a disposizione tool di sviluppo e librerie (sempre Open Source) quali Android Software Developer Kit (SDK) e Native Development Kit (NDK). Come è stato accennato in precedenza, Android OS è stato creato per essere leggero e in grado di supportare dispositivi con hardware differenti. Ma come è strutturato questo sistema operativo? Se guardiamo Android da un punto di vista architetturale, possiamo notare come esso si sviluppa su un’architettura a layer (i livelli inferiori offrono servizi ai livelli superiori). In particolare distinguiamo 4 livelli principali: • Linux Kernel: è il layer più basso e fornisce, attraverso vari driver affidabili, una virtualizzazione dell’hardware. Il motivo della scelta del kernel di Linux iv Introduzione Figura 1: Architettura Android OS deriva dall’esigenza di creare un OS in grado di fornire un livello elevato di sicurezza, una buona gestione della memoria nonché una elevata affidabilità. In questo modo, infatti, il vendor che intende dotare i propri dispositivi di Android non dovrà fare altro che installare il Linux Kernel ed implementare gli opportuni driver compatibili con il proprio hardware; • Librerie native: contiene le librerie native (scritte in C/C++) tra le quali citiamo Surface Manager (si occupa di gestire l’interfaccia grafica e le varie finestre presenti sullo schermo), OpenGL ES (gestisce elementi grafici), SGL(libreria che gestisce prettamente la grafica 2D), Secure Sockel Layer(si occupa della comunicazione sicura su socket). Queste librerie garantiscono, quindi, l’interazione tra l’utente e il dispositivo attraverso la grafica 2D e 3D, l’utilizzo del touch screen e tutto quello che riguarda la multimedialità; • Application Framework(AF): le librerie citate nel punto precedente vengono utilizzate da questo livello: in particolare le AF sono un insieme di API che vengono utilizzate per l’esecuzione di specifiche funzionalità che sono fondamenv Introduzione tali per un’applicazione Android e quindi rappresentano l’impalcatura di una qualsiasi applicazione; • Android Runtime(AR): è il vero e proprio motore di Android OS. E’ costituito dalle cosiddette core libraries e dalla Dalvik Virtual Machine, sostituita da ART nell’ultima release di Android.[3] In questo elaborato verrà approfondito proprio il livello Android Runtime e in particolare si parlerà della Dalvik Virtual Machine (DVM) e di ART, il nuovo runtime system implementato da Google che ha inizialmente affiancato Dalvik in Android 4.0 KitKat, per poi essere utilizzato definitivamente in Android 5.0 Lollipop. vi Capitolo 1 Dalvik Virtual Machine La necessità di garantire un avvio e un tempo di risposta rapido da parte delle applicazioni che girano su hardware con risorse limitate, ha spinto Google a progettare un software in grado di sfruttare al massimo le risorse disponibili: nasce cosı̀ la Dalvik Virtual Machine. La DVM è una macchina virtuale progettata da Dan Bornstein, dipendente di Google, e prende il nome dall’omonimo villaggio di pescatori di cui la famiglia di Bornstein è originaria. Progettata e ottimizzata, infatti, proprio per sfruttare la poca memoria disponibile sui dispositivi mobile, permette a più istanze della macchina virtuale di girare contemporaneamente celando la gestione dei thread e della memoria al sistema operativo[4]: in questo modo si è in grado di semplificare il riutilizzo del codice e di eliminare o quanto meno prevenire problemi di incompatibilità.[5] 1.1 Un’architettura basata su registri Solitamente chi progettava macchine virtuali preferiva utilizzare un’architettura stack-based, impilando tutte le istruzioni all’interno di uno stack. In questo modo, infatti, si andava incontro ad una notevole semplicità di implementazione sia della VM sia dei compilatori back-end (la maggior parte delle macchine virtuali venivano progettate per supportare un unico linguaggio di programmazione). Recenti studi, però, hanno dimostrato che cercare di semplificare le cose ha avuto un costo in termini di perfomance: confrontando, infatti, l’architettura stack-based con quella register based 1 Capitolo 1. Dalvik Virtual Machine (architettura orientata sull’uso dei registri), è risultato che la seconda richiede in media il 47% in meno di istruzioni VM rispetto alla prima ed impiega il 32.3% in meno di tempo per eseguire benchmark standard. Per comprendere meglio la differenza tra le due architetture possiamo fare un esempio molto semplice ma significativo. Consideriamo la seguente espressione[6]: b=c+d Una macchina stack-based traduce questa operazione nel seguente codice JVM(Java Virtual Machine) ILOAD d, ILOAD c, IADD, ISTORE b; In una VM register-based, invece, la stessa espressione si traduce nel seguente codice: IADD a,b,c; E’facile notare come il codice utilizzato da un’architettura register-based è notevolmente ridotto rispetto a quello utilizzato da una VM stack-based anche se, in media, come è stato dimostrato, comporta per una macchina reale l’1.07% di lavoro in più per ogni istruzione a causa di una maggiore lunghezza di queste ultime; il numero di istruzioni da elaborare, dunque, spiega perchè la prima risulta essere nettamente più veloce rispetto alla seconda. Tutto quello che è stato detto fino ad ora spiega il motivo per il quale Google abbia deciso di basare la Dalvik Virtual Machine su un’architettura registered-based: capacità di elaborazione e limiti di memoria, infatti, sono vincoli decisamente rispettati dalla DVM.[7] 2 Capitolo 1. Dalvik Virtual Machine Figura 1.1: Confronto tra JVM e DVM 1.2 File .DEX A causa della molteplicità di applicazioni mobile scritte in linguaggio Java e compatibili con la Java Virtual Machine (JVM), è stato necessario creare un sistema di conversione in grado di garantire la compatibilità e la portabilità delle applicazioni stesse in Android OS. Poiché la JVM si basa su un’architettura stack-based, infatti, è nata la necessità di convertire i file Java compatibili con la JVM in file .dex (Dalvik EXecutable) o .odex (Optimized Dalvik EXecutable) compatibili con la DVM (discendente, peraltro, direttamente dalla JVM), in modo tale da ottimizzare le risorse e soprattutto la memoria (Fig 1.1). Attraverso un tool integrato chiamato dx è possibile, quindi, trasformare il bytecode Java in un nuovo bytecode compatibile con la DVM e convertire i file .class in file .dex. Durante questo processo di conversione, in particolare, si verifica uno snellimento e una vera e propria compressione dei file .dex: in questo modo, infatti, si garantisce il rispetto del vincolo sui limiti di memoria, riducendo drasticamente l’eccessivo spazio che generalmente viene dedicato ai comuni file Java in formato .jar. Più precisamente, questo risultato è stato ottenuto grazie ad un principio di condivisione che provoca una riorganizzazione del file .jar. Quest’ultimo, infatti, è costituito da una serie di file .class (Fig. 1.2), uno per ogni classe, in cui è suddiviso il codice; la ridondanza del codice sta proprio nella mancanza di una struttu- 3 Capitolo 1. Dalvik Virtual Machine ra unitaria, la quale comporta una ripetizione degli oggetti che altrimenti potrebbero essere condivisi in maniera più intelligente ed efficiente in modo da evitare spreco di risorse e memoria. Invocando, quindi, il compilatore attraverso il tool dx, si crea il file .dex che sostituisce completamente la strutta divisa in classi descritta in precedenza con una ordinata solo ed esclusivamente per tipologia di codice.[8] Figura 1.2: Struttura di un file .jar(sinistra) e di un file .dex(destra) Per comprendere meglio quello che è stato detto in precedenza, consideriamo l’esempio presentato al Google I/O nel 2008 dall’ideatore della DVM Dan Bornstein: p u b l i c i n t e r f a c e Zapper { p u b l i c S t r i n g zap ( S t r i n g s , Object o ) ; } p u b l i c c l a s s B l o r t implements Zapper { p u b l i c S t r i n g zap ( S t r i n g s , Object o ) ; .....; } p u b l i c c l a s s ZapUser { 4 Capitolo 1. Dalvik Virtual Machine p u b l i c v o i d useZap ( Zapper z ) { z . zap ( . . . . . ) } } Dalla figura 1.4 possiamo notare come in ogni classe del file .jar sono presenti ripetizioni delle costanti Ljava/lang/String nei metodi Ljava/lang/String; e Ljava/lang/Object che causano un eccessivo spreco di memoria. In un file .DEX, invece, Ljava/lang/String è memorizzata una sola volta poiché si permette alle classi di condividere la Constant Pool (tabella dei simboli per la rappresentazione del class file per ogni classe ed interfaccia) riducendo al minimo l’utilizzo delle costanti. Questa ripetizione minima, però, comporta l’utilizzo di numerosi puntatori logici e/o riferimenti. Figura 1.3: Snellimento del file .jar 1.3 Layout del file .DEX Un file .DEX può essere visto da un punto di vista architetturale come una struttura basata su ben 8 campi, chiamata “Big Header” a causa dell’elevato numero di informazioni in esso contenute: • header: contiene l’header del file .DEX; • string ids: si tratta di una lista che contiene gli identificatori di stringhe. Questi identificatori vengono utilizzati dal file .DEX sia per la denominazione interna 5 Capitolo 1. Dalvik Virtual Machine (ad esempio descrittori) sia per le costanti. La lista deve, inoltre, essere ordinata sulla base del contenuto e non deve contenere identificatori duplicati; • type ids: simile al campo precedente, questa volta si tratta di una lista contenente gli identificatori di tutti i tipi di dato(array, classi, tipi primitivi,ecc). Anche in questo caso, la lista deve essere ordinata sulla base degli identificatori del campo string id e non deve contenere voci duplicate; • proto ids: lista contenente gli identificatori per tutti i prototipi delle funzioni presenti nel file .DEX. L’elenco contenuto in questo campo deve essere rigorosamente ordinato sulla base del tipo di ritorno con maggiore importanza(indice type ids). L’elenco non deve contenere voci duplicate; • field ids: lista contenente gli identificatori di tutti i campi a cui fa riferimento il file .DEX. La lista deve essere ordinata in modo tale da specificare prima il tipo del campo e poi il nome; • method ids: è una lista contenente tutti i metodi a cui fa riferimento il file .DEX e deve essere ordinato nel seguente modo: prima va indicato il tipo del metodo, poi il nome ed infine il prototipo; • class defs: lista contenente le definizioni delle classi. In particolare, essa deve essere ordinata in modo tale che la superclasse di una determinata classe e i suoi metodi vengono visualizzati prima della classe di riferimento; • data: l’area dati contiene tutte quelle informazioni di supporto per le liste descritte nei precedenti punti. E’ importante sottolineare che a questo livello di categoria i vari oggetti hanno esigenze differenti di allineamento: per questo motivo vengono talvolta utilizzati dei byte di riempimento in modo tale da garantire un corretto allineamento. 6 Capitolo 1. Dalvik Virtual Machine 1.4 File ODEX Le applicazioni che vengono installate in Android OS sono disponibili in pacchetti aventi estensione .apk. In particolare, questi pacchetti contengono alcuni file con estensione .ODEX (Optimized Odex) la cui funzione principale è quella di risparmiare spazio. Più precisamente, un file con questa estensione, chiamato anche odexed file, rappresenta quella parte ottimizzata di un’applicazione che permette di eseguire velocemente il boot della stessa. Tutto ciò è possibile grazie al caricamento dell’applicazione all’interno della cosiddetta Dalvik Cache, uno spazio temporaneo che viene utilizzato dalla DVM contenente indirizzi di memoria, struttura delle directory delle app installate e dati vari. Grazie alla creazione dei file .odex, infine, il sistema operativo è in grado di conoscere in anticipo quali applicazioni avviare (le informazioni sono presenti proprio nella Dalvik Cache) in modo da ridurre il tempo di avvio del sistema operativo. Un file ODEX viene creato grazie ad un software chiamato dex2opt. Nella fase di ottimizzazione vengono effettuate una serie di operazioni di snellimento del file .dex: i metodi virtuali, infatti, vengono sostituiti con opportune versioni ottimizzate contenenti l’indice della tabella virtuale del metodo chiamato, in modo da evitare la ricerca nella Virtual Table in fase di esecuzione; vengono potati, inoltre, i metodi vuoti, ossia quei metodi come Object hiniti che vengono utilizzati in fase di allocazione di un oggetto, ecc. Durante la fase di ottimizzazione del file .dex, infine, il software dex2opt ricorre spesso all’indicizzazione poiché permette di ignorare la risoluzione simbolica iniziale e una rapida esecuzione.[9] 1.5 Differenze con la JVM Come è stato già discusso in precedenza, la DVM è nata in seguito all’esigenza di utilizzare una VM in grado di girare su ambienti a memoria ridotta, sfruttando le caratteristiche del sistema. Ma se è vero che si preferisce non sfruttare la VM Java, perché non si è utilizzato almeno il suo byte-code, implementando solo i metodi che servono per la sua interpretazione? Nei paragrafi precedenti, è stato mostrato come il 7 Capitolo 1. Dalvik Virtual Machine codice di un’applicazione Java sia molto ridondante e che un file .dex elimina questi problemi: ad esempio, se un file Java racchiude codice per un totale di 100 Kb, lo stesso potrà essere realizzato in formato .dex pesando circa la metà! Ciò che è stato appena detto, però non è l’unica caratteristica che differenzia la JVM con la DVM. Per quanto riguarda l’Istruction Set, infatti, Dalvik presenta 218 tipologie di opcodes contro i 200 di Java. Per sottolineare ulteriormente la differenza anche a basso livello tra le due macchine virtuali, basti pensare, ad esempio, che Java utilizza una dozzina di opcodes, totalmente assenti in Dalvik, che vengono utilizzati per il trasferimento di dati dallo stack alla lista contenente le variabili locali; inoltre, mentre il bytecode della JVM utilizza più opcodes per effettuare confronti tra oggetti, Dalvik ne utilizza uno solo semplificando ulteriormente le cose. Infine, la JVM dedica opcodes diversi a seconda del tipo di dato mentre la DVM ne mette a disposizione uno uguale per tutti i tipi. Le istruzioni in linguaggio macchina in Dalvik, infine, sono molto più lunghe poichè, trattandosi di un’architettura register-based, contengono sia gli indirizzi di origine che di destinazione dei registri.[10] 1.6 Compilatore JIT A partire dalla versione Android 2.2 Froyo, è stato adottato un compilatore JIT (Just In Time) che interpreta le applicazione nel momento in cui vengono eseguite: con Dalvik, quindi, Android diventa un sistema operativo a compilazione dinamica, in cui il compilatore viene utilizzato anche in fase di esecuzione. Nelle versioni immediatamente precedenti Android 2.2 Froyo, però, Google decise di non adottare un siffatto compilatore: se è vero che la DVM interpreta una sola istruzione alla volta del bytecode, è anche vero che non tutte le istruzioni devono essere tradotte ogni volta che le applicazioni vengono eseguite perché vari elementi, librerie in primis, sono già scritte in linguaggio macchina e quindi il compilatore non deve agire. Alcuni studi, infatti, hanno dimostrato proprio che solo una piccola parte del tempo impiegato per l’esecuzione di un’applicazione viene utilizzato per l’interpretazione del bytecode. A tutto quanto detto fino ad ora va aggiunto, inoltre, l’utilizzo di un bytecode compatto 8 Capitolo 1. Dalvik Virtual Machine e ottimizzato per dispositivi con limiti di risorse e di memoria. Purtroppo, però, la scelta iniziale del colosso di Mountin View si è rivelata infelice in quanto si è andati incontro a seri e fastidiosi rallentamenti in fase di esecuzione. Ma come opera un compilatore JIT? Spesso capita che l’interprete (programma che esegue altri programmi convertendo il codice sorgente il linguaggio macchina) si trovi dinanzi a porzioni di codice intrecciate e abbastanza complicate da un punto di vista computazionale. Il compilatore JIT interviene proprio in queste situazioni, affiancando l’interprete nella traduzione del codice sorgente in linguaggio macchina e ottimizzandolo. Questa operazione di semplificazione si rileva molto efficace perché ogni qual volta si va ad eseguire successivamente queste porzioni di codice, esse si troveranno già tradotte in linguaggio macchina: le prestazioni migliorano notevolmente. Ciò che contraddistingue un buon compilatore JIT, però, è la capacità di capire quando e dove intervenire: quello utilizzato da Android Dalvik, infatti, garantisce un minor utilizzo della memoria e un miglioramento delle prestazioni eliminando quella fastidiosa attesa che si riscontrava nelle prime versioni di Android ogni qual volta si lanciava un’applicazione.[11] Al giorno d’oggi sono molto utilizzati due tipi di compilatori JIT: • Method based: utilizzato da Java, questo compilatore compila in codice nativo e ottimizza i metodi che sono più complessi da un punto di vista computazionale. Poiché viene compilato il metodo per intero, spesso traduce anche porzioni di codice che vengono utilizzate raramente sprecando tempo inutilmente. • Traced based: questo tipo di compilatore, individua solo istruzioni (e non metodi come nel caso precedente) computazionalmente complesse e le raggruppa in tracce; una volta compilate, queste tracce vengono tutte racchiuse in una translation cache: in questo modo, l’esecuzione avviene per tracce successive. 9 Capitolo 1. Dalvik Virtual Machine Figura 1.4: Processo Zygote 1.7 Zygote Tra le varie caratteristiche di Android, assume un ruolo importante in termini di performance la riduzione dell’overhead durante la fase di avvio di un’applicazione in modo da garantire una risposta rapida da parte del dispositivo. La DVM è una macchina virtuale di tipo process: questi tipi di VM sono in grado di eseguire un unico processo alla volta; di conseguenza, per poter eseguire contemporaneamente più applicazioni, devono essere create più istanze di Dalvik Virtual Machine, una per ogni applicazione eseguita. L’overhead, quindi, viene ridotto proprio andando a velocizzare il processo di creazione delle varie istanze attraverso il cosiddetto Zygote, un processo daemon (eseguito in background) inizializzato dal sistema operativo la cui funzione è quella di avviare applicazioni. Il suo avvio è innescato da init.rc dopo Service Manager , ma in realtà è iniziato da app process. Consideriamo, a tal proposito, la sequenza di istruzioni necessarie per avviare un processo di questo tipo: s e r v i c e z y g o t e / system / b i n / a p p p r o c e s s −Xzygote / system / b i n −−z y g o t e −−s t a r t −system−s e r v e r c l a s s main s o c k e t z y g o t e stream 660 r o o t system 10 Capitolo 1. Dalvik Virtual Machine o n r e s t a r t w r i t e / s y s / a n d r o i d p o w e r / r e q u e s t s t a t e wake o n r e s t a r t w r i t e / s y s / power / s t a t e on o n r e s t a r t r e s t a r t media o n r e s t a r t r e s t a r t netd Notiamo come il processo Zygote viene avviato come system service e come l’app process sia effettivamente l’istruzione che lo avvia: più precisamente, quest’ultima crea la prima istanza di DVM ed effettua una chiamata al metodo main() di Zygote. Una volta che esso è stato avviato, quindi, non solo vengono caricate tutte le risorse e le classi Java necessaria ma viene avviato anche il System Server, il quale apre una socket /dev/socket/zigote in modo tale da mettersi in ascolto per eventuali richieste di avvio da parte delle varie applicazioni. Quali sono, quindi, le operazioni che vengono fatte dal processo Zygote per avviare le applicazioni? Quando viene ricevuta una richiesta di avvio tramite la suddetta socket, lo Zygote effettua una fork() dando vita ad una nuova istanza di DVM precaricata con tutte quelle risorse e quelle classi che sono necessarie ad ogni applicazione (Fig. 1.4). Poiché Android utilizza un kernel Linux, viene implementata una stategia chiamata Copy On Write (COW): quando lo Zygote effettua una fork, non viene effettuata nessuna copia della memoria in un altro spazio, ma viene condivisa e marcata come copy-on-write, ovvero quando un processo di un’applicazione cerca di accedere e modificare quell’area di memoria, il kernel intercetta la chiamata e ne crea una copia che potrà essere opportunamente modificate. In altre parole, si ritiene non necessario creare una copia della memoria ogni qual volta viene effettuata una fork(), ma solo nel momento in cui un processo richiede di poter modificare le informazioni in essa contenute.[12] 11 Capitolo 1. Dalvik Virtual Machine 1.8 Garbage Collector La garbage collection (letteralmente raccolta dei rifiuti) rappresenta un modo automatico di gestire la memoria grazie alla quale un compilatore o il sistema operativo è in grado di liberare quei blocchi di memoria che, precedentemente referenziati (ovvero allocate da un processo o utilizzate da un’applicazione), non vengono più utilizzati e quindi possono essere utilizzate da altri processi; il Garbage Collector, quindi, annoterà queste aree e le libererà automaticamente. Grazie al Garbage Collector, il programmatore viene esonerato dal preoccuparsi del quantitativo di memoria da allocare per la sua applicazione e soprattutto di doverla successivamente deallocare. Purtroppo, però, come sarà descritto in seguito, un sistema automatico per la gestione della memoria non sempre si comporta bene. In Android Dalvik, il processo di gestione della memoria da parte del Garbage Collector viene dettata da due pause: la prima pausa avviene durante la fase di enumerazione in cui si contano i blocchi di memoria da liberare, mentre la seconda si verifica durante la fase di marcatura. Per pausa, in questo caso, si intende l’arco di tempo in cui viene letteralmente sospesa l’esecuzione del codice di un’applicazione e di tutti i suoi thread. Se la pausa è troppo lunga, l’applicazione rallenta eccessivamente la sua esecuzione a causa della perdita di numerose frame, rendendo pessima l’user experience. Google sostiene che una durata media di queste pause si aggira intorno ai 54 ms per un LG Nexus 5, comportando la perdita di almeno 4 frames ogni volta che il Garbage Collector si attiva. In realtà, come dimostrato da Andrei Frumusanu, la durata di una pausa dipende soprattuto dal tipo di applicazione avviata. Consideriamo, a questo proposito, il seguente esempio riportato dallo stesso Andrei Fumusanu sul sito www.anandtech.com [13]: 07-01 15:56:14.275: D/dalvikvm(30615): GC FOR ALLOC freed 4442K, 25% free 20183K/26856K, paused 24ms, total24ms 07-01 15:56:16.785: I/dalvikvm-heap(30615): Grow heap (frag case) to 38.179MB for 8294416-byte allocation 07-01 15:56:17.225: I/dalvikvm-heap(30615): Grow heap (frag case) to 48.279MB for 7361296-byte allocation 07-01 15:56:17.625: I/Choreographer(30615): Skipped 35 frames! The application may be doing too much work on its main thread.ù 07-01 15:56:19.035: D/dalvikvm(30615): GC CONCURRENT freed 35838K, 43% free 51351K/89052K, paused 3ms+5ms, total 106ms 07-01 15:56:19.035: D/dalvikvm(30615): WAIT FOR CONCURRENT GC blocked 96ms 07-01 15:56:19.815: D/dalvikvm(30615): GC CONCURRENT freed 7078K, 42% free 52464K/89052K, paused 14ms+4ms, total 96ms 12 Capitolo 1. Dalvik Virtual Machine 07-01 15:56:19.815: D/dalvikvm(30615): WAIT FOR CONCURRENT GC blocked 74ms 07-01 15:56:20.035: I/Choreographer(30615): Skipped 141 frames! The application may be doing too much work on its main thread. 07-01 15:56:20.275: D/dalvikvm(30615): GC FOR ALLOC freed 4774K, 45% free 49801K/89052K, paused 168ms, total 168ms 07-01 15:56:20.295: I/dalvikvm-heap(30615): Grow heap (frag case) to 56.900MB for 4665616-byte allocation 07-01 15:56:21.315: D/dalvikvm(30615): GC FOR ALLOC freed 1359K, 42% free 55045K/93612K, paused 95ms, total 95ms 07-01 15:56:21.965: D/dalvikvm(30615): GC CONCURRENT freed 6376K, 40% free 56861K/93612K, paused 16ms+8ms, total 126ms 07-01 15:56:21.965: D/dalvikvm(30615): WAIT FOR CONCURRENT GC blocked 111ms 07-01 15:56:21.965: D/dalvikvm(30615): WAIT FOR CONCURRENT GC blocked 97ms 07-01 15:56:22.085: I/Choreographer(30615): Skipped 38 frames! The application may be doing too much work on its main thread. 07-01 15:56:22.195: D/dalvikvm(30615): GC FOR ALLOC freed 1539K, 40% free 56833K/93612K, paused 87ms, total 87ms 07-01 15:56:22.195: I/dalvikvm-heap(30615): Grow heap (frag case) to 60.588MB for 1331732-byte allocation 07-01 15:56:22.475: D/dalvikvm(30615): GC FOR ALLOC freed 308K, 39% free 59497K/96216K, paused 84ms, total 84ms 07-01 15:56:22.815: D/dalvikvm(30615): GC FOR ALLOC freed 287K, 38% free 60878K/97516K, paused 95ms, total 95ms Si tratta di un estratto del registro di un’applicazione dopo i primi secondi dal suo avvio. Possiamo notare come il Garbage Collector venga richiamato per 9 volte causando il blocco dell’applicazione per un totale di 603 ms e una perdita di ben 214 frame. La maggior parte delle pause sono dovute alle varie richieste di allocazione da parte della memoria, come indicato dal tag ”GC FOR ALLOC”. Il funzionamento del Garbage Collector utilizzato da Android Dalvik, infine, si basa sull’approccio “march and sweep”. Secondo questo approccio, viene mantenuta una lista contenente tutti quei blocchi della memoria heap contrassegnati come liberi. Nel momento in cui un processo richiede l’allocazione di un blocco libero e la lista risulta vuota, il Garbage Collector si comporta nel seguente modo: • utilizza dei bit per marcare quegli oggetti che sono ancora in uso e che quindi non dovrebbero essere rimossi. Questi bit vengono memorizzati in un’area separata all’interno della memoria heap; • riordina e raccoglie tutti i blocchi non marcati e li inserisce all’interno della lista vuota. Più precisamente, il funzionamento dell’algoritmo può essere riassunto nel seguente pseudo-codice: 13 Capitolo 1. Dalvik Virtual Machine f o r each r o o t v a r i a b l e r mark ( r ) ; sweep ( ) ; Per poter distinguere gli oggetti in uso da quelli che possono essere eliminati, ognuno di essi contiene un campo booleano che indica lo stato marked(true) o unmarked(false). Generalmente tutti gli oggetti quando vengono creati risultano unmarked di default. Un generico oggetto p e tutti quelli che sono accessibili indirettamente attravero p vengono marcati attraverso un’operazione ricorsiva: v o i d mark ( Object p ) { i f ( ! p . marked ) p . marked = t r u e ; f o r each Object q r e f e r e n c e d by p mark ( q ) ; Questo algoritmo ricorsivo non fa niente se incontra oggetti che risultano già marcati; di conseguenza termina nel momento in cui tutti gli oggetti accessibili risultano marked. Nella seconda fase l’algoritmo “mark and sweep” scansiona tutti gli oggetti nella memoria heap in modo tale da localizzare tutti quelli che risultano unmarked. In particolare, la memoria allocata per gli oggetti non marcati viene recuperata durante la fase di scansione, mentre il campo booleano degli oggetti che sono stati segnati in precedenza come marked viene settato a false per la successva invocazione dell’algoritmo. Le operazioni effettuate durante la fase di “sweep” sono riportate in seguito: v o i d sweep ( ) f o r each Object p i n t h e heap i f ( p . marked ) p . marked = f a l s e e l s e heap . r e l e a s e ( p ) ; [ 1 4 ] 14 Capitolo 2 Android Runtime (ART) Quando Android Dalvik fu creato, i dispositivi possedevano un hardware dalle prestazioni molto limitate: processori single core che garantivano scarse performance, memoria flash e RAM molto limitata costrinsero Google a dar vita ad macchina virtuale con un bytecode compatto, un Garbage Collector poco sofisticato e soprattutto ottimizzato per sistemi monoprocessore. Oggi, però, i tempi sono cambiati! La tecnlologia ha fatto passi da gigante, sono stati creati dispositivi mobile multiprocessore, addirittura fino ad 8 core, che hanno portato ad un miglioramento fino a 50x in termini di CPU performance; esistono dispositivi che supportano fino a 4 gigabyte di RAM, una risoluzione dello schermo molto elevata e una memoria flash le cui dimensioni sono quadruplicate rispetto ai tempi di Android Dalvik. Insomma, l’inesorabile avanzare della tecnologia ha portato il team di Google a fissare degli obiettivi molto importanti che salvaguardassero, allo stesso tempo, anche i dispositivi più datati. Si è cercato di rendere le applicazioni più fluide e con meno lag grazie ad una compilazione rapida e ad un codice ancora più snello che non ricorre alla JNI e quindi al codice nativo. E’ nato cosı̀ Android Runtime (ART). 2.1 Miglioramenti apportati Google ha sempre avuto come obiettivo principale quello di rendere Android una piattaforma fluida e funzionale anche su quei dispositivi più datati che faticano a sta15 Capitolo 2. Android Runtime (ART) re al passo con i tempi. Android Runtime nasce proprio in questa ottica: garantisce migliore gestione delle risorse e prestazioni migliorate grazie alla modalità di compilazione ahead-of-time (AOT) che effettua la traduzione del codice sorgente in linguaggio macchina durante la fase di installazione delle applicazioni e non durante l’esecuzione della stessa. ART garantisce, inoltre, un miglior utilizzo della batteria -punto critico per ogni sistema operativo e grana che affligge la maggior parte degli utenti- grazie a due motivi principali. Il primo è dovuto proprio alla tecnologia AOT che permette una sola volta la compilazione di un’applicazione, a differenza della tecnologia JIT che comporta la compilazione della stessa ogni qual volta la si avvia, causando una inevitabile perdita di tempo e utilizzo di risorse. Una sola compilazione, infatti, elimina il problema della perdita dei cicli della CPU dovuta all’avvio del processo di compilazione all’atto di ogni esecuzione: tutto ciò si traduce in un minor tempo di alimentazione della CPU e a intervalli di tempo in cui il dispositivo opera in una modalità a basso consumo. In secondo luogo, ART ricorre all’utilizzo di un codice ancora più snello e performante che riduce nettamente il battery drain perché è possibile aumentare e diminuire velocemente la frequenza di utilizzo del processore. Viene migliorato, infine, la gestione della memoria RAM rafforzando i principi su cui si fonda Project Svelte, un progetto che mira a rendere Android OS sempre più performante anche su quei dispositivi con 512 Mb di RAM. Poiché Dalvik permetteva la compilazione di un’applicazione solo quando questa veniva eseguita, il codice non veniva mai scritto sul disco ma veniva mantenuto in memoria: in una situazione in cui la memoria libera era poca, i processi venivano killati e di conseguenza il codice compilato andava perso. Se l’utente, quindi, riavviava l’applicazione, il processo di compilazione doveva ricominciare da capo. Grazie ad ART, invece, i dati ed il codice possono essere paginati su richiesta perché, come detto in precedenza, il codice viene compilato in fase di installazione: se sono presenti molte applicazioni in esecuzione su un dispositivo (multitasking), quindi, il kernel è in grado di gestire la pagine in maniera efficiente caricandole in memoria soltanto se e quando necessario. ART, inol- 16 Capitolo 2. Android Runtime (ART) tre, è in grado di pre-inizializzare durante la fase di compilazione un insieme di classi creando un file chiamato boot.art (mappato in memoria) che comprende anche oggetti correlati. Nonostante questa operazione provochi un consumo aggiuntivo (all’incirca 10 Mb), si riesce ad ottenere un avvio più rapido e si da la possibilità al sistema operativo di scambiare alcune classi pre-caricate in memoria, migliorando ulteriormente le prestazioni di accesso alla memoria RAM. Non c’è più, infine, cache di codice runtime in quanto i file .ELF vengono mappati direttamente in memoria. Potrebbe sembrare, quindi, che la memoria RAM occupata risulti essere maggiore in proporzione al Set Size, ma si hanno dei netti miglioramenti in termini di memoria reale rispetto alla Dalvik cache.[15] 2.2 DEX2OAT Figura 2.1: Confronto tra la conversione in Android Dalvik e ART DEX2OAT è un tool che viene utilizzato in ART per evitare che un’applicazione ottimizzata per Dalvik venga nuovamente riscritta: questo tool, infatti, effettua una conversione del bytecode Dalvik (file .dex) in un file con formato eseguibile. Dalla 17 Capitolo 2. Android Runtime (ART) figura 2.1 sopra riportata, è possibile notare come le operazioni di conversione siano simili a quelle effettuate dal tool dex2opt descritto nel capitolo precedente: l’unica differenza consiste nella diversa tipologia di file ( .ELF file) che si ottiene dal risultato della conversione. Per capire come funzione e cosa fa questo tool possiamo sfruttare l’opzione di runtime switch da Dalvik a ART messa a disposizione da Google su Android 4.4 KitKat. Il cambio di runtime richiede il reboot del dispositivo, seguito poi da una fase di avvio che richiede diversi minuti in quanto il tool dex2opt effettua un upgrade delle applicazioni di sistema. In seguito vengono riportate le varie operazioni: I/art(123): GenerateImage: /system/bin/dex2oat –image=/data/dalvik-cache/system@[email protected]@classes.dex– runtime-arg-Xms64m–runtime-arg-Xmx64m–dex-file=/system/framework/core-libart.jar–dex-file=/system/framework/ conscrypt.jar– dex-file=/system/framework/okhttp.jar–dex-file=/system/framework/core-junit.jar–dex-file=/ system/framework/bouncycastle.jar– dex-file=/system/framework/ext.jar–dex-file=/system/framework/ framework.jar–dex-file=/system/framework/framework2.jar– dex-file=/system/framework/ telephony-common.jar–dex-file=/system/framework/voip-common.jar –dex-file=/system/framework/ mms-common.jar–dex-file=/system/framework/android.policy.jar –dex-file=/system/framework/ services.jar–dex-file=/system/framework/apache- xml.jar –dex-file=/ system/framework/ webviewchromium.jar–oat-file=/data/dalvik-cache/system@[email protected]@classes.oat- -base=0x60000000–image-classes-zip=/system/framework/framework.jar–image-classes=preloaded-classes Possiamo notare che viene creato un processo chiamato “art”, avviato dal system server, che crea un file immagine utilizzando il tool. Per come è strutturata la commandline, possiamo dividerla in varie parti: • alcuni argomenti di runtime per una VM; • una serie di file .dex che vengono compilati all’interno dell’immagine; • output del file oat; • un file jar contenente le classi che dovrebbero essere compilate nell’immagine; • uno specificatore che descrive quali classi devono essere utilizzate all’interno del file jar. Durante la creazione dell’immagine vengono, quindi, compilati tutti i file .dex relativi alle applicazioni di sistema.[16] 18 Capitolo 2. Android Runtime (ART) 2.3 Struttura del file .ELF E’ stato già detto che ART utilizza in ingresso lo stesso bytecode utilizzato dalla Dalvik Virtual Machine garantendo, quindi, una piena compatibilità con i file .dex. Sparisce, però, il file .odex, il quale viene rimpiazzato da quello con estensione .ELF (Executable and Linkable Format) che si viene a creare nel momento in cui viene installata e quindi compilata un’applicazione. ELF (Fig 2.2) è un formato di file standard per eseguibili, file oggetto e librerie ed è costituita da una serie di sezioni e segmenti; le prime contengono quei dati che sono necessari per le operazioni di linkaggio e di rilocazione, mentre le seconde contengono tutte quelle informazioni che sono necessarie per l’esecuzione. Tutte le informazioni riguardante la struttura interna del file (ad esempio gli indirizzi delle altre sezioni) sono contenute all’interno di un header. Più precisamente, all’interno dell’header distinguiamo due campi: Figura 2.2: file .ELF • Program Header Table: contiene le informazione relative ai vari segmenti del file .ELF. E’ un campo che può essere opzionale in fase di linkaggio, ma estremamente necessario in fase di compilazione perché deve istruire quei programmi che si occupano della creazione dell’immagine del processo e di caricare il file .ELF nel modo corretto; 19 Capitolo 2. Android Runtime (ART) • Section Header Table: contiene le informazioni che descrivono le sezioni del file. Android RunTime utilizza i file ELF in maniera leggermente diversa rispetto al suo classico utilizzo in quanto non ricorre all’uso dei simboli per trovare ogni singolo entry point: solitamente un programma Java usa un numero elevato di metodi e assegnare un simbolo ad ognuno di essi sarebbe un’operazione eccessivamente onerosa. Ciò che fa ART, invece, consiste nell’andare ad utilizzare una struttura dati che permette di caricare velocemente i metodi di una determinata classe: quando, infatti, questa struttura è stata caricata, è possibile facilmente trovare e collegare i metodi e gli oggetti di una certa classe in modo da poter eseguire il codice rapidamente. ART, infine, ricorre all’utilizzo di alcune sezioni del file ELF come contenitori dei metadati utili per il caricamento delle classi o per altri scopi come il debugging. 2.4 Compilazione Ahead-Of-Time (AOT) Figura 2.3: Processo di compilazione in ART 20 Capitolo 2. Android Runtime (ART) Come già è stato accennato in precedenza, la compilazione ahead-of-time sposta la fase di compilazione durante la fase di installazione delle applicazioni: il codice java, infatti, viene compilato in codice binario nativo per la piattaforma hardware attraverso il tool DEX2OAT. Questo nuovo tipo di compilazione, però, occupa spazio (è stata adottata soltanto oggi grazie alle maggiori dimensioni di archiviazione dei dispositivi mobili) e allunga i tempi di installazione delle applicazioni stesse. Una caratteristica principale del compilatore ahead-of-time utilizzato da ART è la parallelizzazione delle operazioni di compilazione (Fig. 2.3). In particolare, la fase introduttiva coincide con l’estrazione dei file .dex da processare. La prima operazione che viene fatta è chiamata class resolution: durante questa fase il compilatore apprende informazioni relative al layout delle classi che successivamente vengono caricate insieme ai loro metodi e ai loro campi. La seconda operazione effettuata viene chiamata class verification e va ad effettuare una verifica delle classi marcandole se essa non ha successo. Più precisamente viene utilizzato un class-file verifier che ha il compito di garantire la robustezza di un’applicazione, assicurando che tutte le classi caricate abbiano una struttura appropriata, onde evitare spiacevoli crash della Virtual Machine. La verifica che viene fatta si articola solitamente in due fasi: • internal checks: durante questa fase il class-verifier verifica se il class file sia stato costruito adeguatamente, sia consisteste, non sia troncato e se rispetta i vincoli del linguaggio Java. In caso contrario quel class file non verrà mai utilizzato in fase di esecuzione; • verifica dei riferimenti simbolici: viene controllata la correttezza dei iferimenti simbolici e se i simbolo vengono risolti correttamente (dynamic linking). La maggior parte delle volte la verifica ha esito positivo ma talvolta può capitare che l’esito sia negativo: ART è stato introdotto in via del tutto sperimentale in Android 4.4 KitKat ed è diventato runtime di default solamente con l’ultima release, Android Lollipop; supponiamo, quindi, di voler installare un’applicazione ottimizzata per Android Lollipop su un dispositivo che ha come sistema operativo Android KitKat e che utilizza 21 Capitolo 2. Android Runtime (ART) ART come runtime. Durante la fase di compilazione viene fatto riferimento alle API compatibili con la “L relase”: in questa situazione può capitare che la verifica fallisce e che quei metodi non compatibili con KitKat vengono marcati come “non verificati”. La compilazione va avanti lo stesso, ma potrebbe capitare che, durante l’esecuzione, l’applicazione smetta di funzionare correttamente perché potrebbe far riferimento a codice che non è presente nella release sulla quale gira. Subito dopo abbiamo la fase di inizializzazione delle classi che setta le variabili in esse contenute con i loro opportuni valori iniziali, ed infine abbiamo la vera e propria compilazione. Qual è quindi la differenza, in termini di prestazioni, tra compilazione JIT e AOT? Innanzitutto, la prima è in grado di eseguire lo stesso codice su vari dispositivi, mentre la seconda ne effettua l’ottimizzazione per un singolo device. In altre parole, mentre ART per garantire una maggiore velocità di esecuzione e migliorare le prestazioni nell’utilizzo di uno specifico dispositivo aumenta percettibilmente i tempi di installazione delle applicazioni, la DVM propone un codice molto più generico che viene eseguito alla stessa maniera su qualunque tipo di dispositivo. In secondo luogo, ART è stato progettato per supportare dispositivi con architetture a 64-bit in quanto Google ha voluto elevare il livello del sistema operativo in modo tale da supportare i moderni dispositivi dotati da architetture con una maggior potenza di calcolo. 2.5 Garbage Collector Con Android RunTime anche il Garbage Collector riceve una profonda rivoluzione. In primo luogo, mentre la DVM utilizza un GC che agisce in due pause, quello in ART ne utilizza solo una che dura attorno ai 2 ms. Inoltre è stato parallelizzato l’avvio del GC e sono state ottimizzate le strategie di raccolta delle informazione sullo stato del dispositivo. Ad esempio solo se il dispositivo si trova in standby e non vi è interazione con l’utente il GC lavora a pieno ritmo: si tratta di un enorme miglioramento per quelle applicazioni che sono sensibili alla perdita di frame.[17] Infine il GC di ART è molto compatto in quanto sposta i chunk di memoria allocata in blocchi contigui in 22 Capitolo 2. Android Runtime (ART) modo da ridurre la frammentazione e l’esigenza di eliminare applicazioni che si trovano da più tempo in modo da liberare spazio necessario allocare grandi zone di memoria. Ciò che ART fornisce, quindi, è un profondo rinnovamento del sistema di Garbage Collection. A tal proposito riprendiamo l’esempio di Andrei Fumusanu fornito nel paragrafo 1.8. La stessa applicazione è stata lanciata su un dispositivo che utilizza come runtime ART e ha prodotto il seguente log: 7-01 16:00:44.531: I/art(198): Explicit concurrent mark sweep GC freed 700(30KB) AllocSpace objects, 0(0B) LOS objects, 792% free, 18MB/21MB, paused 186us total 12.763ms 07-01 16:00:44.545: I/art(198): Explicit concurrent mark sweep GC freed 7(240B) AllocSpace objects, 0(0B) LOS objects, 792% free, 18MB/21MB, paused 198us total 9.465ms 07-01 16:00:44.554: I/art(198): Explicit concurrent mark sweep GC freed 5(160B) AllocSpace objects, 0(0B) LOS objects, 792% free, 18MB/21MB, paused 224us total 9.045ms 07-01 16:00:44.690: I/art(801): Explicit concurrent mark sweep GC freed 65595(3MB) AllocSpace objects, 9(4MB) LOS objects, 810% free, 38MB/58MB, paused 1.195ms total 87.219ms 07-01 16:00:46.517: I/art(29197): Background partial concurrent mark sweep GC freed 74626(3MB) AllocSpace objects, 39(4MB) LOS objects, 1496% free, 25MB/32MB, paused 4.422ms total 1.371747s 07-01 16:00:48.534: I/Choreographer(29197): Skipped 30 frames! The application may be doing too much work on its main thread. 07-01 16:00:48.566: I/art(29197): Background sticky concurrent mark sweep GC freed 70319(3MB) AllocSpace objects, 59(5MB) LOS objects, 825% free, 49MB/56MB, paused 6.139ms total 52.868ms 07-01 16:00:49.282: I/Choreographer(29197): Skipped 33 frames! The application may be doing too much work on its main thread. 07-01 16:00:49.652: I/art(1287): Heap transition to ProcessStateJankImperceptible took 45.636146ms saved at least 723KB 07-01 16:00:49.660: I/art(1256): Heap transition to ProcessStateJankImperceptible took 52.650677ms saved at least 966KB La differenza tra ART e Dalvik è rilevante in quanto la nuova runtime fa intervenire il GC solo 6 volte provocando pause per un totale di soli 12,346 ms e una perdita di sole 63 frames. Infine, ART ricorre all’uso di un memory allocator completamente nuovo chiamato Rosalloc(Runs of Slots Allocator). La maggior parte dei moderni sistemi operativi utilizza allocator basati su Doug Lea’s design il quale utilizza un singolo memory lock globale che mette in attesa tutti quei thread che per poter procedere all’esecuzione devono entrare in possesso di uno specifico oggetto. Se un thread non può acquisire immediatamente il lock si mette in attesa che questo diventi libero oppure abbandona la sezione protetta; in un ambiente mulithread e object-oriented ciò può creare conflitti tra thread interferenze con il GC. In Rossalloc, invece, gli oggetti condivisi vengono allocati senza memory locking mentre quelli di grandi dimensioni hanno una propria are heap e un lock indipendente dagli altri che riduce i conflitti e migliora le operazioni 23 Capitolo 2. Android Runtime (ART) di parallelismo. Per questo motivo quando un’applicazione tenta di allocare memoria per un nuovo oggetto non deve aspettare che il GC libera una regione di memoria. 24 Conclusioni In questo elaborato si è cercato di sottolineare quali sono gli aspetti fondamentali dei due runtime utilizzati in Androis OS. La Dalvik Virtual Machine nasce in seguito all’esigenza di rendere quanto più portabile possibile il sistema operativo Android e cercare di minimizzare i problemi riguardo all’incompatibilità dei dispositivi; Android RunTime, d’altro canto, nasce semplicemente come miglioramento della DVM e va ad eliminare quella “macchinosità” che ha accompagnato l’user-experience fino ad Android 4.0 KitKat. Grazie ai miglioramenti apportati da ART, infatti, Android OS diventa a tutti gli effetti una piattaforma in grado di supportare sia dispositivi con limiti hardware, sia dispositivi di fascia alta in grado di fornire una corposa interfaccia utente. ART è, quindi, il risultato di un enorme sforzo da parte di Google fatto per portare Android un passo avanti rispetto alla concorrenza: un nuovo Garbage Collector, compilazione ahead-of-time e un nuovo allocation manager hanno finalmente contribuito a garantire performance elevate e un’esperienza utente molto soddisfacente, lasciando alle spalle tutta una serie fastidiosissima di lag e microlag che hanno caratterizzato le versioni precedenti del “robottino verde”. 25 Bibliografia [1] http://it.wikipedia.org/wiki/Android [2] Ben Elgin, Google Buys Android for Its Mobile Arsenal in Bloomberg Businessweek, 17 agosto 2005 [3] Introduzione ad Android - http://www.apogeonline.com/2011/libri/ 9788850330737/allegati/public/capitolo1.pdf [4] http://en.wikipedia.org/wiki/Dalvik [5] Michele Nasi, Android accantonerà Dalvik e migliorerà le performance con ART, 11 Novembre 2013 http://www.ilsoftware.it/articoli.asp?tag=Android-accantonera-Dalvike-migliorera-le-performance-con-ART 10414 [6] http://www.megaoverclock.it/blogs/blog1.php/terza-lezione-dalvikseconda-parte [7] Mark Sinnathamby, Stack based vs Register Virtual Machine Architecture and the DAlvik https://markfaction.wordpress.com/2012/07/15/stack-based-vsregister-based-virtual-machine-architecture-and-the-dalvik-vm/ [8] Dan Bornstein, Dalvik VM http://sites.google.com/site/io/dalvik-vm-internals Internals based VM, - [9] AndroidWorld, Android dalla A alla Z: cosa sono odexed/deodexed? - http://www.androidworld.it/il-dizionario-di-android/android-dalla-aalla-z-cosa-sono-odexeddeodexed/ [10] Comparison of Dalvik and Java Bytecode http://forensics.spreitzenbarth.de/2012/08/27/comparison-of-dalvikand-java-bytecode/ [11] Jorge Suarez Rivaya, ”Zygote” - http://anatomyofandroid.com/2013/10/15/zygote/ [12] Google I/O 2010 - http://www.android-app-developer.co.uk/androidapp-development-docs/android-jit-compiler-androids-dalvik-vm.pdf 26 Bibliografia [13] Andrei Frumusanu,A Closer Look at Android RunTime (ART) in Android L http://www.anandtech.com/show/8231/a-closer-look-atandroid-runtime-art-in-android-l/2 [14] Bruno R.Preiss, P.Eng, ”Mark-and-Sweep Garbage Collection” http://www.brpreiss.com/books/opus5/html/page424.html [15] Matthias Schaff, What is ART - https://plus.google.com/+MatthiasSchaff /posts/U1jhMAv3d7R [16] Runtime ART - http://www.ldldroid.it/android/153-runtime-art.html [17] Jason Snell, Android Runtime Performance Analysis Using New Relic: ART vs. Dalvik - https://blog.newrelic.com/2014/07/07/android-art-vsdalvik/ 27