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