Dalvik: какво е, виртуалната машина и как работи

Автор: IT Sectr Публикувано: 2026-04-16 Време за четене: 9 мин

Виртуалната машина Dalvik е ключов компонент на операционната система Android, отговаряла за изпълнението на приложения до версия 4.4 KitKat. Разработената от Дан Борнщайн VM с регистрова архитектура замени концепцията на стандартната JVM и позволи да се оптимизира стартирането на приложения на мобилни устройства с ограничен обем оперативна памет. По данни на Google, 2024, Dalvik осигуряваше съвместимостта на приложенията чрез JIT компилация, преобразувайки DEX байткода в машинни инструкции непосредствено по време на изпълнение.

Накратко

  • Dalvik е виртуална машина с регистрова архитектура, оптимизирана за Android.
  • За разлика от JVM, Dalvik изпълнява DEX байткод, специално компресиран за мобилни устройства.
  • JIT компилацията преобразува част от DEX кода в машинен директно по време на работата на приложението.
  • От Android 5.0 Dalvik е заменена с ART с предварителна AOT компилация.
  • Разбирането на Dalvik е необходимо за поддръжка на стари версии на Android и анализ на обратната съвместимост.

Какво е Dalvik?

Dalvik е виртуална машина с регистрова архитектура, създадена специално за платформата Android. Разработката започва през 2005 г. от компанията на Дан Борнщайн, а през 2007 г. проектът е закупен от Google. Първата търговска версия на Dalvik се появява заедно с излизането на Android 1.0 през 2008 г.

За разлика от стандартната Java Virtual Machine (JVM), Dalvik не изпълнява Java байткод. Компилаторът на Java преобразува изходния код в class файлове, а след това помощната програма dx ги превежда във формат Dalvik Executable (DEX). Този формат е по-компактен от class файловете: едно приложение с размер 10 MB в class формат заема приблизително 6–7 MB в DEX.

История на създаването

Дан Борнщайн написва Dalvik като проект за операционни системи с ограничени ресурси. Името е взето от исландското село Далвик. Google избира Dalvik вместо JVM поради лицензионни ограничения и необходимостта от дълбока оптимизация за мобилни процесори с ARM архитектура. Системата бързо набира популярност: до 2012 г. над 500 милиона Android устройства работят с Dalvik.

Роля в екосистемата на Android

Всяко Android приложение се стартира в отделен процес със собствена инстанция на Dalvik VM. Това осигурява изолация на данните и защита от злонамерен код на ниво операционна система. Този подход съчетава предимствата на виртуализацията с пясъчника на Linux — зловреден софтуер в едно приложение не може да повлияе на съседните процеси.

Архитектура на Dalvik: регистрова машина и DEX

Регистровата архитектура на Dalvik принципно се различава от стековата архитектура на JVM. Вместо операции с върха на стека, Dalvik работи с регистри — виртуални клетки вътре във VM. Всяка инструкция съдържа адресите на регистрите-операнди, което намалява броя на инструкциите за една операция.

Стековата машина на JVM използва инструкции като push, pop и add — за събирането на две числа са нужни три инструкции. Dalvik решава същата задача с една инструкция add-int с три регистъра. По данни на Android Open Source Project, регистровата архитектура на DEX намалява обема на байткода средно с 30% в сравнение със стековия class формат.

Форматът DEX

DEX файлът (Dalvik Executable) съдържа компресирано представяне на всички класове на приложението. Заглавната част на файла включва контролна сума, размери на секциите и отмествания. Основните секции са пуловете от низове, типове, прототипи на методи, полета и самият байткод. В един DEX файл могат да се съхраняват до 65536 метода (ограничението е отпаднало с въвеждането на multi-dex в Android 5.0).

За преобразуването на class файлове в DEX се използва помощната програма dx, включена в Android SDK Build Tools. Пример за команда: dx --dex --output=classes.dex myapp.jar. Съвременните проекти използват D8 — наследника на dx с подобрена оптимизация и поддръжка на функции от Java 8+.

bash
# Преобразуване на JAR в DEX с помощта на dx
dx --dex --output=classes.dex myapp.jar

# Съвременна версия чрез D8
d8 --lib android.jar --output dex/ myapp.jar

Zygote: предварително зареждане на рамката

Процесът Zygote е най-важният елемент от архитектурата на Dalvik. При стартиране на системата Zygote зарежда всички класове на Android SDK, отваря споделените библиотеки и създава пул от preload ресурси. Когато потребителят отвори приложение, системата копира (fork) процеса Zygote, създавайки нова инстанция на Dalvik VM с вече готова рамка. Това намалява времето за стартиране на приложението от ~2–3 секунди до 300–500 милисекунди.

JIT компилация в Dalvik

JIT (Just-In-Time) е технология за компилиране на байткод в машинни инструкции непосредствено по време на изпълнението на приложението. В Dalvik JIT компилаторът анализира изпълнявания DEX код, открива често използваните (hot) методи и ги компилира в нативен код за CPU.

Изборът на JIT вместо пълна Ahead-Of-Time (AOT) компилация в ранните версии на Android е съзнателен. Мобилните устройства са имали ограничен обем флаш памет (4–16 GB) — предварителната компилация на всички приложения би заела значително място. Освен това ROM паметта в ранните устройства е била по-бавна от оперативната и четенето на предварително компилиран код би могло да намали производителността.

Процес на JIT компилация

Когато приложението се стартира, Dalvik започва да интерпретира DEX байткода. Специален профилатор проследява кои методи се извикват най-често. След превишаване на прага (обикновено ~200 извиквания) JIT компилаторът преобразува метода в машинен код и го кешира в оперативната памет. Следващите извиквания използват вече компилираната версия без повторна компилация.

java
// Пример за hot метод, който JIT ще компилира
public class Calculator {
    public int sumArray(int[] arr) {
        int total = 0;
        for (int i = 0; i < arr.length; i++) {
            total += arr[i];
        }
        return total;
    }
}

Производителност на JIT

По данни на Google I/O 2013, въвеждането на JIT в Android 2.2 Froyo е ускорило изпълнението на приложения средно 2–5 пъти в сравнение с чистата интерпретация. Все пак JIT добавя забавяне при първото стартиране: на приложението са нужни от 3 до 10 секунди за загряване и компилиране на hot методите. След загряването производителността се стабилизира на ниво, близко до нативния код.

Dalvik срещу JVM: ключови разлики

Dalvik се различава от JVM по няколко основни параметъра. Първо — архитектурата: JVM е стекова, Dalvik — регистрова. Второ — форматът на байткода: JVM използва class файлове, Dalvik — DEX. Трето — управлението на паметта: Dalvik е оптимизирана за ограничения обем RAM на мобилните устройства.

И двата подхода имат силни страни. Стековата JVM изисква по-малко място за съхранение на инструкции — всяка инструкция е по-къса, тъй като операндите се вземат имплицитно от стека. Регистровата Dalvik изпълнява по-малко инструкции за една операция, което спестява процесорно време и намалява консумацията на енергия. За мобилните устройства с батерийно захранване това е критично.

ПараметърDalvikJVM
АрхитектураРегистроваСтекова
БайткодDEXclass
КомпилацияJIT (Android 2.2+)JIT / AOT
ОптимизацияНиска консумация на енергияВисока съвместимост
ИзолацияЧрез Linux процесиЧрез ClassLoader

Лицензионни аспекти

Изборът на Dalvik вместо JVM е обусловен и от лицензирането. Oracle притежава правата върху Java SE и JVM, а Google се е стремяла да избегне лицензионните плащания. Създаването на собствена VM с алтернативен формат на байткода позволи на Android да се развива независимо от Oracle. Този спор прераства в многогодишен съдебен процес Oracle срещу Google (2010–2021), завършил в полза на Google.

Форматът DEX и помощната програма dx

DEX (Dalvik Executable) е двоичен формат, съдържащ компилирания код на Android приложението. Всеки DEX файл започва със заглавна част (header), след която следват секциите: низови константи (string_ids), типове (type_ids), прототипи на методи (proto_ids), полета (field_ids), методи (method_ids), дефиниции на класове (class_defs) и област за данни (data).

Помощната програма dx преобразува Java class файловете в един или няколко DEX файла. Алгоритъмът на работа включва дедупликация на константи — еднаквите низове или типове се съхраняват веднъж и се реферират по индекс. Това значително намалява крайния размер. В съвременните проекти dx е заменена с D8 (появява се в Android Studio 3.1), която работи 2–3 пъти по-бързо и поддържа desugaring за Java 8.

java
// Пример за декомпилиран DEX байткод чрез dexdump
// Изходен код: return a + b;
@Ldalvik/annotation/Code;
    registers: 3
    add-int v0, v1, v2
    return v0

Multi-dex: преодоляване на лимита 65536

Ограничението на DEX формата до 65536 метода (лимитът на 16-битовия индекс) се превръща в сериозен проблем за големите приложения. Решението се появява в Android 5.0: поддръжката на multi-dex позволява приложението да съдържа няколко DEX файла. Основният classes.dex съдържа входните точки, а допълнителните classes2.dex, classes3.dex и така нататък — останалия код. Конфигурацията на multi-dex се включва в build.gradle с реда multiDexEnabled true.

Управление на паметта и събиране на отпадъци

Събирането на отпадъци в Dalvik е реализирано като поколенчески (generational) събирач с маркиране и изчистване (mark-and-sweep). Паметта се разделя на две основни области: Heap (купчина) за обектите и Stack (стек) за примитивите и референциите. При запълване на Heap Dalvik спира всички нишки (STW — Stop-The-World), маркира достижимите обекти и освобождава недостижимите.

Преди Android 2.2 Dalvik използва еднонишков събирач с продължителност на паузите до 100–200 ms. В Android 2.3 Gingerbread се появява concurrent-събирачът, който намалява типичните паузи до 5–10 ms. А в Android 4.0 Ice Cream Sandwich е добавен събирач с частично (incremental) изчистване — Concurrent Mark and Sweep (CMS).

Изтичане на памет

Типичен проблем на Dalvik приложенията е изтичането на памет чрез статични референции към Activity. Ако статично поле съхранява референция към Context или View, събирачът на отпадъци не може да освободи Activity дори след затваряне на екрана. Инструменти като Eclipse MAT и LeakCanary помагат да се открият подобни течове: те анализират дамп на Heap и показват веригите от референции, които задържат обекта.

java
// Пример за изтичане на памет чрез статична референция
public class Utils {
    private static Context context;

    public static void init(Context ctx) {
        context = ctx; // Задържа Activity след finish()
    }
}

Ограничения на Dalvik и преминаването към ART

Въпреки успеха си, Dalvik има редица недостатъци. JIT компилацията изисква време за загряване — първите секунди от работата на приложението са по-бавни. Освен това JIT изразходва процесорна енергия при компилирането, което намалява времето за автономна работа. С нарастването на производителността на мобилните устройства и увеличаването на обема на вградената памет нуждата от JIT намалява.

В Android 4.4 KitKat Google представя ART (Android Runtime) като експериментална замяна на Dalvik. От Android 5.0 Lollipop ART става единствената среда за изпълнение. Основната разлика е AOT компилацията: вместо компилиране по време на работа, всички приложения се компилират в машинен код при инсталирането. Това премахва забавянията при загряване и подобрява енергийната ефективност.

Обратна съвместимост

Преминаването от Dalvik към ART е прозрачно за разработчиците: и двете среди изпълняват един и същ DEX байткод. Приложенията, създадени за Dalvik, работят на ART без прекомпилиране — system_server ги компилира в нативен код при инсталирането. Изключение е кодът, който използва рефлексия за достъп до вътрешни членове на Dalvik VM: такъв код може да се счупи на ART поради промяна на вътрешната архитектура.

Често задавани въпроси

Какво е Dalvik с прости думи?

Dalvik е програма-посредник, която стартира Android приложенията на телефона. Тя взема кода на приложението и го превръща в команди, разбираеми за процесора, правейки това директно по време на работата на потребителя.

С какво Dalvik се различава от JVM?

Dalvik използва регистрова архитектура и формат DEX, а JVM — стекова архитектура и формат class. Dalvik е оптимизирана за мобилни устройства с ограничена памет и процесор, докато JVM е създадена за стационарни компютри и сървъри.

Защо Google замени Dalvik с ART?

ART осигурява по-висока производителност чрез предварителна AOT компилация — приложението се компилира веднъж при инсталирането, а не всеки път при стартиране. Това ускорява работата и пести батерия в сравнение с JIT подхода на Dalvik.

Работят ли старите приложения на ART?

Да, ART е напълно обратно съвместим с DEX байткода на Dalvik. При инсталирането ART компилира старите DEX файлове в нативен код. Изключение правят приложенията, които използват рефлексия за достъп до вътрешните механизми на Dalvik.

Какво е DEX файл?

DEX (Dalvik Executable) е формат на изпълним файл, съдържащ компресирания байткод на Android приложението. В един APK може да има няколко DEX файла (multi-dex), ако приложението съдържа повече от 65536 метода.

Изводи

  • Dalvik VM е регистрова виртуална машина, създадена за Android и използвана до версия 4.4 KitKat.
  • Форматът DEX осигурява компактно съхранение на байткода — с 30% по-малко от class файловете на JVM.
  • JIT компилацията в Dalvik ускорява изпълнението на приложения 2–5 пъти в сравнение с чистата интерпретация.
  • Процесът Zygote предварително зарежда рамката на Android, намалявайки стартирането на приложения до 300–500 ms.
  • Ограничението от 65536 метода в един DEX файл се решава чрез multi-dex от Android 5.0.
  • Събирането на отпадъци в Dalvik изминава път от еднонишков STW до Concurrent Mark and Sweep.
  • Преминаването към ART в Android 5.0 премахва забавянията при загряване на JIT и подобрява енергийната ефективност.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също