Dalvik: co to jest, maszyna wirtualna i jak działa

Autor: IT Sectr Opublikowano: 2026-04-16 Czas czytania: 9 min

Maszyna wirtualna Dalvik — kluczowy komponent systemu operacyjnego Android, odpowiedzialny za wykonywanie aplikacji aż do wersji 4.4 KitKat. Opracowana przez Dana Bornsteina maszyna rejestrowa VM zastąpiła koncepcję standardowej JVM i pozwoliła zoptymalizować uruchamianie aplikacji na urządzeniach mobilnych z ograniczoną ilością pamięci RAM. Według danych Google, 2024, Dalvik zapewniała kompatybilność aplikacji poprzez JIT-kompilację, przekształcając DEX-kod bajtowy w instrukcje maszynowe bezpośrednio podczas wykonywania.

Najważniejsze

  • Dalvik — maszyna wirtualna z architekturą rejestrową, zoptymalizowana dla Androida.
  • W przeciwieństwie do JVM, Dalvik wykonuje DEX-kod bajtowy, specjalnie skompresowany dla urządzeń mobilnych.
  • JIT-kompilacja przekształca część kodu DEX na maszynowy bezpośrednio podczas działania aplikacji.
  • Począwszy od Androida 5.0 Dalvik został zastąpiony przez ART z wstępną kompilacją AOT.
  • Zrozumienie Dalvik jest niezbędne do obsługi starych wersji Androida i analizy kompatybilności wstecznej.

Co to jest Dalvik?

Dalvik — maszyna wirtualna z architekturą rejestrową, stworzona specjalnie dla platformy Android. Rozwój rozpoczął się w 2005 roku w firmie Dana Bornsteina, a w 2007 roku projekt został przejęty przez Google. Pierwsza komercyjna wersja Dalvik pojawiła się wraz z wydaniem Androida 1.0 w 2008 roku.

W przeciwieństwie do standardowej Java Virtual Machine (JVM), Dalvik nie wykonuje Java-kodu bajtowego. Kompilator Java przekształca kod źródłowy w pliki class, a następnie narzędzie dx tłumaczy je na format Dalvik Executable (DEX). Ten format jest bardziej kompaktowy niż pliki class: pojedyncza aplikacja o rozmiarze 10 MB w formacie class zajmuje około 6–7 MB w DEX.

Historia powstania

Dan Bornstein napisał Dalvik jako projekt dla systemów operacyjnych z ograniczonymi zasobami. Nazwa pochodzi od islandzkiej wioski Dalvík. Google wybrała Dalvik zamiast JVM ze względu na ograniczenia licencyjne i potrzebę głębokiej optymalizacji pod procesory mobilne z architekturą ARM. System szybko zdobył popularność: do 2012 roku na Dalvik działało ponad 500 milionów urządzeń z Androidem.

Rola w ekosystemie Android

Każda aplikacja Android uruchamiana jest w oddzielnym procesie z własną instancją Dalvik VM. Zapewnia to izolację danych i ochronę przed złośliwym kodem na poziomie systemu operacyjnego. Takie podejście łączy zalety wirtualizacji z piaskownicą Linux — złośliwe oprogramowanie w jednej aplikacji nie może wpłynąć na sąsiednie procesy.

Architektura Dalvik: maszyna rejestrowa i DEX

Architektura rejestrowa Dalvik zasadniczo różni się od architektury stosowej JVM. Zamiast operacji na wierzchołku stosu, Dalvik operuje na rejestrach — wirtualnych komórkach wewnątrz VM. Każda instrukcja zawiera adresy rejestrów operandów, co zmniejsza liczbę instrukcji na jedną operację.

Maszyna stosowa JVM używa instrukcji takich jak push, pop i add — do dodania dwóch liczb potrzebne są trzy instrukcje. Dalvik rozwiązuje to samo zadanie jedną instrukcją add-int z trzema rejestrami. Według danych Android Open Source Project, architektura rejestrowa DEX zmniejsza objętość kodu bajtowego średnio o 30% w porównaniu z formatem stosowym class.

Format DEX

Plik DEX (Dalvik Executable) zawiera skompresowaną reprezentację wszystkich klas aplikacji. Nagłówek pliku zawiera sumę kontrolną, rozmiary sekcji i przesunięcia. Główne sekcje to pule stringów, typów, prototypów metod, pól i sam kod bajtowy. W jednym pliku DEX może być przechowywanych do 65536 metod (ograniczenie zniesione przez wprowadzenie multi-dex w Android 5.0).

Do konwersji plików class na DEX używa się narzędzia dx, wchodzącego w skład Android SDK Build Tools. Przykład polecenia: dx --dex --output=classes.dex myapp.jar. Nowoczesne projekty używają D8 — następcy dx z ulepszoną optymalizacją i obsługą funkcji Java 8+.

bash
# Konwersja JAR do DEX za pomocą dx
dx --dex --output=classes.dex myapp.jar

# Nowoczesna wersja przez D8
d8 --lib android.jar --output dex/ myapp.jar

Zygote: wstępne ładowanie frameworka

Proces Zygote — najważniejszy element architektury Dalvik. Podczas uruchamiania systemu Zygote ładuje wszystkie klasy Android SDK, otwiera wspólne biblioteki i tworzy pulę zasobów preload. Gdy użytkownik otwiera aplikację, system kopiuje proces Zygote (fork), tworząc nową instancję Dalvik VM z gotowym frameworkiem. Skraca to czas uruchamiania aplikacji z ~2–3 sekund do 300–500 milisekund.

Kompilacja JIT w Dalvik

JIT (Just-In-Time) — technologia kompilacji kodu bajtowego na instrukcje maszynowe bezpośrednio podczas wykonywania aplikacji. W Dalvik kompilator JIT analizuje wykonywany kod DEX, identyfikuje często używane (hot) metody i kompiluje je do kodu natywnego dla CPU.

Wybór JIT zamiast pełnej kompilacji Ahead-Of-Time (AOT) we wczesnych wersjach Androida był świadomy. Urządzenia mobilne miały ograniczoną ilość pamięci flash (4–16 GB) — wstępna kompilacja wszystkich aplikacji zajęłaby znaczną przestrzeń. Ponadto pamięć ROM we wczesnych urządzeniach działała wolniej niż pamięć operacyjna, a odczytywanie wcześniej skompilowanego kodu mogło obniżyć wydajność.

Proces kompilacji JIT

Gdy aplikacja jest uruchamiana, Dalvik zaczyna interpretować kod bajtowy DEX. Specjalny profiler śledzi, które metody są wywoływane najczęściej. Po przekroczeniu progu (zwykle ~200 wywołań) kompilator JIT przekształca metodę w kod maszynowy i zapisuje go w pamięci RAM. Kolejne wywołania korzystają już ze skompilowanej wersji bez ponownej kompilacji.

java
// Przykład metody hot, którą JIT skompiluje
public class Calculator {
    public int sumArray(int[] arr) {
        int total = 0;
        for (int i = 0; i < arr.length; i++) {
            total += arr[i];
        }
        return total;
    }
}

Wydajność JIT

Według danych Google I/O 2013, wdrożenie JIT w Android 2.2 Froyo przyspieszyło działanie aplikacji średnio 2–5 razy w porównaniu z czystą interpretacją. Jednak JIT dodaje opóźnienie przy pierwszym uruchomieniu: aplikacja potrzebuje od 3 do 10 sekund na rozgrzanie i kompilację metod hot. Po rozgrzaniu wydajność stabilizuje się na poziomie bliskim kodowi natywnemu.

Dalvik vs JVM: kluczowe różnice

Dalvik różni się od JVM w kilku fundamentalnych parametrach. Po pierwsze — architektura: JVM jest stosowa, Dalvik jest rejestrowa. Po drugie — format kodu bajtowego: JVM używa plików class, Dalvik — DEX. Po trzecie — zarządzanie pamięcią: Dalvik jest zoptymalizowany pod ograniczoną ilość RAM urządzeń mobilnych.

Oba podejścia mają mocne strony. Stosowa JVM wymaga mniej miejsca na przechowywanie instrukcji — każda instrukcja jest krótsza, ponieważ operandy są niejawnie pobierane ze stosu. Rejestrowa Dalvik wykonuje mniej instrukcji na jedną operację, co oszczędza czas procesora i zmniejsza zużycie energii. Dla urządzeń mobilnych zasilanych bateryjnie jest to krytyczne.

ParametrDalvikJVM
ArchitekturaRejestrowaStosowa
Kod bajtowyDEXclass
KompilacjaJIT (Android 2.2+)JIT / AOT
OptymalizacjaNiskie zużycie energiiWysoka kompatybilność
IzolacjaPrzez procesy LinuxPrzez ClassLoader

Aspekty licencyjne

Wybór Dalvik zamiast JVM był również podyktowany licencjonowaniem. Oracle posiada prawa do Java SE i JVM, a Google chciała uniknąć opłat licencyjnych. Stworzenie własnej VM z alternatywnym formatem kodu bajtowego pozwoliło Androidowi rozwijać się niezależnie od Oracle. Spór ten przerodził się w wieloletni proces sądowy Oracle vs Google (2010–2021), zakończony na korzyść Google.

Format DEX i narzędzie dx

DEX (Dalvik Executable) — format binarny zawierający skompilowany kod aplikacji Android. Każdy plik DEX rozpoczyna się od nagłówka (header), po którym następują sekcje: stałe łańcuchowe (string_ids), typy (type_ids), prototypy metod (proto_ids), pola (field_ids), metody (method_ids), definicje klas (class_defs) i obszar danych (data).

Narzędzie dx przekształca pliki Java class w jeden lub kilka plików DEX. Algorytm działania obejmuje deduplikację stałych — identyczne łańcuchy lub typy są zapisywane raz i odwołują się przez indeks. To znacząco zmniejsza końcowy rozmiar. W nowoczesnych projektach dx została zastąpiona przez D8 (pojawiła się w Android Studio 3.1), która działa 2–3 razy szybciej i obsługuje desugaring Java 8.

java
// Przykład zdekompilowanego kodu bajtowego DEX przez dexdump
// Kod źródłowy: return a + b;
@Ldalvik/annotation/Code;
    registers: 3
    add-int v0, v1, v2
    return v0

Multi-dex: przezwyciężenie limitu 65536

Ograniczenie formatu DEX do 65536 metod (limit 16-bitowego indeksu) stało się poważnym problemem dla dużych aplikacji. Rozwiązanie pojawiło się w Android 5.0: obsługa multi-dex pozwala aplikacji zawierać kilka plików DEX. Główny classes.dex zawiera punkty wejścia, a dodatkowe classes2.dex, classes3.dex i tak dalej — resztę kodu. Konfiguracja multi-dex jest włączana w build.gradle linią multiDexEnabled true.

Zarządzanie pamięcią i zbieranie śmieci

Zbieranie śmieci w Dalvik jest zaimplementowane jako pokoleniowy (generational) zbieracz z oznaczaniem i czyszczeniem (mark-and-sweep). Pamięć dzieli się na dwa główne obszary: Heap (sterta) dla obiektów i Stack (stos) dla typów prostych i referencji. Przy wypełnieniu sterty Dalvik wstrzymuje wszystkie wątki (STW — Stop-The-World), oznacza osiągalne obiekty i zwalnia nieosiągalne.

Do Androida 2.2 Dalvik używała jednowątkowego zbieracza z czasem wstrzymania do 100–200 ms. W Android 2.3 Gingerbread pojawił się współbieżny zbieracz, skracający typowe wstrzymania do 5–10 ms. A w Android 4.0 Ice Cream Sandwich dodano zbieracz z częściowym (incremental) czyszczeniem — Concurrent Mark and Sweep (CMS).

Wycieki pamięci

Typowy problem aplikacji Dalvik — wycieki pamięci przez statyczne referencje do Activity. Jeśli statyczne pole przechowuje referencję do Context lub View, zbieracz śmieci nie może zwolnić Activity nawet po zamknięciu ekranu. Narzędzia takie jak Eclipse MAT i LeakCanary pomagają wykrywać takie wycieki: analizują zrzut sterty i pokazują łańcuchy referencji utrzymujących obiekt.

java
// Przykład wycieku pamięci przez statyczną referencję
public class Utils {
    private static Context context;

    public static void init(Context ctx) {
        context = ctx; // Przechowuje Activity po finish()
    }
}

Ograniczenia Dalvik i przejście na ART

Pomimo sukcesu, Dalvik miał szereg wad. JIT-kompilacja wymagała czasu na rozgrzanie — pierwsze sekundy działania aplikacji były wolniejsze. Ponadto JIT zużywał energię procesora podczas kompilacji, co skracało czas pracy na baterii. Wraz ze wzrostem wydajności urządzeń mobilnych i zwiększeniem ilości wbudowanej pamięci, potrzeba JIT zmalała.

W Android 4.4 KitKat Google przedstawiła ART (Android Runtime) jako eksperymentalny zamiennik Dalvik. Począwszy od Androida 5.0 Lollipop ART stał się jedynym środowiskiem wykonawczym. Główna różnica — kompilacja AOT: zamiast kompilacji podczas działania, wszystkie aplikacje są kompilowane do kodu maszynowego przy instalacji. To wyeliminowało opóźnienia rozgrzewania i poprawiło efektywność energetyczną.

Kompatybilność wsteczna

Przejście z Dalvik na ART było przezroczyste dla programistów: oba środowiska wykonują ten sam DEX-kod bajtowy. Aplikacje zbudowane dla Dalvik działają na ART bez ponownej kompilacji — system_server kompiluje je do kodu natywnego przy instalacji. Wyjątkiem jest kod używający refleksji do dostępu do wewnętrznych elementów Dalvik VM: taki kod mógł się zepsuć na ART z powodu zmiany architektury wewnętrznej.

Często zadawane pytania

Co to jest Dalvik prostymi słowami?

Dalvik — to program-pośrednik, który uruchamia aplikacje Android na telefonie. Bierze kod aplikacji i przekształca go w polecenia zrozumiałe dla procesora, robiąc to bezpośrednio podczas pracy użytkownika.

Czym Dalvik różni się od JVM?

Dalvik używa architektury rejestrowej i formatu DEX, podczas gdy JVM używa architektury stosowej i formatu class. Dalvik jest zoptymalizowany dla urządzeń mobilnych z ograniczoną pamięcią i procesorem, podczas gdy JVM jest przeznaczona dla komputerów stacjonarnych i serwerów.

Dlaczego Google zastąpiła Dalvik ART?

ART zapewnia wyższą wydajność dzięki wstępnej kompilacji AOT — aplikacja jest kompilowana raz podczas instalacji, a nie każdym razem przy uruchomieniu. To przyspiesza działanie i oszczędza baterię w porównaniu z podejściem JIT w Dalvik.

Czy stare aplikacje działają na ART?

Tak, ART jest w pełni kompatybilny wstecz z DEX-kodem bajtowym Dalvik. Podczas instalacji ART kompiluje stare pliki DEX do kodu natywnego. Wyjątkiem są aplikacje używające refleksji do dostępu do wewnętrznych mechanizmów Dalvik.

Co to jest plik DEX?

DEX (Dalvik Executable) — format pliku wykonywalnego zawierającego skompresowany kod bajtowy aplikacji Android. W jednym APK może być kilka plików DEX (multi-dex), jeśli aplikacja zawiera więcej niż 65536 metod.

Podsumowanie

  • Dalvik VM — rejestrowa maszyna wirtualna stworzona dla Androida i używana aż do wersji 4.4 KitKat.
  • Format DEX zapewnia kompaktowe przechowywanie kodu bajtowego — o 30% mniej niż pliki class JVM.
  • Kompilacja JIT w Dalvik przyspieszała działanie aplikacji 2–5 razy w porównaniu z czystą interpretacją.
  • Proces Zygote wstępnie ładuje framework Androida, skracając uruchamianie aplikacji do 300–500 ms.
  • Ograniczenie 65536 metod w jednym pliku DEX jest rozwiązywane przez multi-dex począwszy od Androida 5.0.
  • Zbieranie śmieci w Dalvik przeszło drogę od jednowątkowego STW do Concurrent Mark and Sweep.
  • Przejście na ART w Android 5.0 wyeliminowało opóźnienia rozgrzewania JIT i poprawiło efektywność energetyczną.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również