ART - największa zmiana w Androidzie od czasu Androida [cz. 2]

ART - największa zmiana w Androidzie od czasu Androida [cz. 2]

Android & ART
Android & ART
Źródło zdjęć: © androidpolice.com
Michał Mynarski
01.07.2014 20:35, aktualizacja: 01.07.2014 22:35

Wirtualne maszyny, jak każde oprogramowanie, mogą się różnić implementacją, wykorzystanymi technologiami czy innymi smaczkami. Dla użytkownika często są one niewidoczne, dla deweloperów czy architektów systemu okazują się zaś kluczowe w pracy. Dalvik i jemu podobne nie należą do wyjątków.

Rodzaje maszyn wirtualnych

Jednym z podziałów, jaki możemy zastosować przy maszynach wirtualnych, jest podział ze względu na implementację. Są VM oparte na stosie lub rejestrach. Czym jest stos, a czym rejestry? Co bardziej uważni czytelnicy, pamiętający mój wpis o A7 zapewne kojarzą rejestry jako najmniejsze, a zarazem najszybsze komórki pamięci wewnątrz procesora, na którym krzem bezpośrednio operuje. Prócz rejestrów procesory mają również stosy. Podobnie jak w przypadku tych pierwszych jest stos odpowiedzialny ze operacje ogólnego przeznaczenia oraz stos specjalny, pod obliczenia na liczbach zmiennoprzecinkowych, tzw. stos FPU. To wszystko, o czym przeczytacie poniżej, jest programową implementacją takich struktur.

Maszyny wirtualne oparte na stosie

Stos (ang. stack) jest strukturą danych, którą można sobie wyobrazić jako nałożone jedna na drugą komórki pamięci, zawierające dane potrzebne dla obliczeń. Te ostatnie umieszcza się na stosie poprzez operacje POP/STORE i ściąga za pomocą operacji PUSH/LOAD. Bezpośrednio obliczenia wykonuje się na szczytowych komórkach stosu, chociaż bardzo często ISA (Instruction Set Architecture) daje do ręki programistom asemblera szeroki wachlarz operacji, nieograniczający się tylko do dwóch "najwyższych wartości". W przypadku wirtualnej maszyny tylko od twórców zależy, jaki zakres instrukcji zaimplementują w VM.

Schemat obrazuje w uproszczony sposób wykonanie instrukcji dodawania 7 i 9 na stosie.
Schemat obrazuje w uproszczony sposób wykonanie instrukcji dodawania 7 i 9 na stosie.© własne

By wykonać proste dodawanie, trzeba wrzucić obie wartości na stos (ze względu na przemienność dodawania - w dowolnej kolejności), zlecić operację dodania (która zsumuje wartości szczytowe, tj. pierwszą i drugą), a jej wynik zostanie przechowany w komórce zerowej. Jak się domyślacie, w efekcie stos "skróci się" o jedną wartość.

Przykładami maszyn wirtualnych opartych na stosie są np. CLR (Common Language Runtime - architektura .NET, czyli język C# i Windows) czy maszyna wirtualna Javy (ale nie Dalvik!).

Maszyny wirtualne oparte na rejestrach

Drugim rodzajem VM są maszyny oparte na rejestrach. Główna i dość oczywista różnica to brak stosu, a co za tym idzie - brak operacji służących do manipulowania danymi. Ale jest przecież ich zastępstwo - wszystkie pochodne instrukcji pozwalających przenosić dane między zmiennymi a rejestrami.

By wykonać dodawanie, należy wpisać lub przenieść żądane wartości za pomocą dwóch operacji ładowania danych, następnie wykonać instrukcję ADD, która może wynik dodawania zachować w jednym z rejestrów służących do przechowania czynników formuły lub w osobnym, trzecim.

Schemat obrazuje w uproszczony sposób implementacji dodawania w maszynie wirtualnej opartej o rejestry.
Schemat obrazuje w uproszczony sposób implementacji dodawania w maszynie wirtualnej opartej o rejestry.© własne

Oczywiście powyższy opis jest uproszczony, bo zarówno operacje na stosie, jak i na rejestrach mają wiele smaczków i detali, do których programista musi przywiązywać wagę (np. w asemblerze wykorzystanie odpowiednich sufiksów opisujących, jakiej długości dane przenosimy etc.). Jednak nie o kod asemblerowy, tylko o koncept tu chodzi!

Jak zapewne się domyślacie, obie implementacje mają swoje wady i zalety. Maszyna wirtualna oparta na stosie jest chętnie wybierana przez inżynierów ze względu na łatwość adresacji danych, ale obsługa operacji składowania ich na stosie może wymuszać niepotrzebne cykle pamięci. Z kolei maszyna oparta na rejestrach pozwala zredukować ilość kodu i wprowadzić niedostępne dla stosu optymalizacje, ale same instrukcje są dłuższe (instrukcja add zawiera co najmniej dwa rejestry z czynnikami).

Dalvik

O maszynach wirtualnych wiecie już całkiem dużo, pora więc odpowiedzieć sobie na najważniejsze pytanie: jaką pozycję zajmuje wśród nich osławiony Dalvik.

Dalvik jest maszyną wirtualną JIT (Just in Time) opartą na modelu rejestrów. JIT z kolei oznacza, że kompilacja porcji kodu odbywa się wtedy, gdy takie polecenie idzie od "góry". Gdy odpalamy aplikację na Androidzie, nie cały jej kod jest interpretowany od razu, tylko jego początkowa część. W miarę przechodzenia przez kolejne funkcje programu odpowiednie, kolejne porcje kodu są kompilowane "w locie".

Dlaczego Google zdecydował się na VM opartą na rejestrach, podczas gdy Java Virtual Machine jest stack-based? Maszyna wirtualna oparta na stosie radzi sobie lepiej na architekturze o niewielkiej liczbie rejestrów i ma mniej rygorystyczne wymagania co do hardware'u. Android w miażdżącej większości jest uruchamiany na procesorach o architekturze ARM, która ma więcej rejestrów ogólnego przeznaczenia niż intelowska IA32. Sam Google podczas I/O 2008 punktował zalety Dalvika, konkretnie Dan Bornstein (twórca Dalvika). Wymienił on m.in. nawet do 30% mniej instrukcji.

Każda nowo odpalona aplikacja (proces) inicjuje nową instancję Dalvika (maszyna wirtualna typu procesowego). Gdy uruchamiamy Androida, następuje boot systemu. Jednym z procesów jest utworzenie Dalvika rodzica, głównej instancji, która będzie "klonowana" (ang. forked) przy każdym żądaniu RunTime'u Androida (ale nie ART!). Dzięki takiemu rozdzieleniu błąd i zabicie jednego procesu nie ma wpływu na działanie reszty systemu.

Jak już wiecie, Dalvik interpretuje kod Javy. W związku z tym nasuwa się pytanie, czym różni się on od Java Virtual Machine. Otóż JVM kompiluje kod źródłowy (Java Source Code) do bytecode'u (Java bytecode) i dopiero on jest wykonywany przez maszynę wirtualną.

Dalvik najpierw kompiluje kod źródłowy Javy do jej bytecode'u, potem uruchamia kompilator DEX, który przepisuje go na bytecode Dalvika i dopiero ten jest wykonywany przez maszynę wirtualną. Poniżej wykres obrazujący tę różnicę:

Diagram obrazujący różnice działania Dalvika od standardowej maszyny wirtualnej Javy (JVM).
Diagram obrazujący różnice działania Dalvika od standardowej maszyny wirtualnej Javy (JVM).© własne

Zapytacie zapewne: skoro Dalvik okazuje się tak niewydajny i problematyczny, dlaczego stał się głównym elementem systemu, który lada moment będzie świętował swoją obecność na miliardzie urządzeń? By odpowiedzieć na to pytanie, musimy cofnąć się w czasie do momentu premiery pierwszych Androidów.

Smartfony miały wówczas znacznie mniej pamięci flash i dużo mniej pamięci RAM, a w takich warunkach kompilacja Just In Time jest lepszym wyborem niż Ahead of Time. Czym jest ta druga i jaki ma to związek z ART? O tym przeczytacie w części trzeciej. Bądźcie czujni!

Źródło artykułu:WP Komórkomania
Oceń jakość naszego artykułuTwoja opinia pozwala nam tworzyć lepsze treści.
Wybrane dla Ciebie
Komentarze (0)