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 МБ у class-форматі займає приблизно 6–7 МБ у DEX.

Історія створення

Ден Борнштейн написав Dalvik як проект для операційних систем з обмеженими ресурсами. Назва взята від ісландського села Дальвік. Google вибрала Dalvik замість JVM через ліцензійні обмеження та необхідність глибокої оптимізації під мобільні процесори з ARM-архітектурою. Система швидко завоювала популярність: до 2012 року на Dalvik працювало понад 500 мільйонів Android-пристроїв.

Роль в екосистемі 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-ресурсів. Коли користувач відкриває додаток, система копіює процес Zygote (fork), створюючи новий екземпляр 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 ГБ) — попередня компіляція всіх додатків зайняла б значне місце. Крім того, 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 vs 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 рази швидше та підтримує 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 мс. У Android 2.3 Gingerbread з'явився concurrent-збирач, що скоротив типові паузи до 5–10 мс. А в 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 мс.
  • Обмеження 65536 методів в одному DEX-файлі вирішується через multi-dex починаючи з Android 5.0.
  • Збирання сміття в Dalvik пройшло шлях від однопотокового STW до Concurrent Mark and Sweep.
  • Перехід на ART в Android 5.0 усунув затримки прогріву JIT та покращив енергоефективність.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також