DEX: що це, структура та принцип роботи байт-коду

Автор: IT Sectr Опубліковано: 2026-04-15 Час читання: 8 хв

DEX (Dalvik Executable) — це формат байт-коду, в який компілюється вихідний код Android-додатків на Java та Kotlin. Файли DEX виконуються віртуальною машиною Dalvik (до Android 4.4) або Android Runtime (ART, починаючи з Android 5.0). За даними Android Open Source Project, 2026, формат DEX забезпечує в середньому 30% більш компактне представлення коду порівняно зі стандартним Java-байткодом JVM.

Головне

  • DEX — формат байт-коду для Android, який виконується на Dalvik або ART.
  • Компактність — DEX займає на 30% менше місця, ніж стандартний Java bytecode.
  • Multidex — механізм для обходу ліміту в 65536 методів в одному DEX-файлі.
  • ART — Android Runtime, що замінив Dalvik, компілює DEX у нативний код при встановленні.
  • D8 — сучасний компілятор Java/Kotlin у DEX, що замінив DX з 2018 року.

Що таке DEX і для чого він потрібен

DEX (Dalvik Executable) — це формат байт-коду, розроблений спеціально для мобільних пристроїв Android. На відміну від стандартного Java-байт-коду (.class файли), DEX оптимізований для обмежених ресурсів: менше пам'яті, менший розмір та швидше завантаження класів.

Від Java до DEX

Вихідний код на Java або Kotlin компілюється javac/kotlinc у стандартні .class файли (Java bytecode). Потім інструмент d8 (або раніше dx) конвертує .class в один або кілька DEX-файлів. Ця конвертація не проста перепаковка — d8 виконує оптимізації: об'єднує константні пули, перезаписує інструкції в регістрову архітектуру та видаляє дубльовані дані.

Архітектурні особливості

DEX використовує регістрову архітектуру (на відміну від стекової JVM). Кожен метод має фіксовану кількість регістрів (до 65536). Інструкції DEX коротші — в середньому 2 байти проти 1–4 байтів у JVM. Це дає більш компактний код: типовий додаток зменшується з 10–15 МБ .class до 4–6 МБ .dex.

Структура DEX-файлу: секції та заголовок

Файл DEX має строго визначену бінарну структуру. Кожен файл починається із заголовка та містить кілька секцій, які посилаються одна на одну через зміщення.

СекціяПризначення
headerЗаголовок: magic, контрольна сума, підпис, розміри та зміщення секцій
string_idsТаблиця рядків: імена класів, методів, полів
type_idsТипи: посилання на рядкові ідентифікатори типів
proto_idsПрототипи методів: тип, що повертається, та параметри
field_idsПоля класів: клас, тип, ім'я
method_idsМетоди: клас, прототип, ім'я
class_defsВизначення класів: прапорці, superclass, інтерфейси, зміщення даних
dataФактичні дані: код методів, анотації, debug info

Заголовок DEX

Магічне число DEX — `dex\n035\0` (версія 035). Інші версії: 036, 037, 038 (для Android 8.0+). Заголовок розміром 0x70 байт містить контрольну суму SHA-1 та зміщення всіх секцій. Валідація заголовка — перший крок при завантаженні DEX віртуальною машиною.

Пули констант

string_ids, type_ids, proto_ids, field_ids, method_ids — це індексовані таблиці. Замість зберігання повних імен у коді методу використовується 4-байтовий індекс. Це ключова оптимізація: якщо клас згадується 100 разів, його ім'я зберігається один раз у string_ids. dex2oat при компіляції ART додатково оптимізує ці таблиці.

Процес компіляції Java та Kotlin у DEX

Процес перетворення вихідного коду в DEX складається з кількох етапів. Сучасний ланцюжок використовує компілятор D8, який прийшов на зміну DX у 2018 році з Android Gradle Plugin 3.2.

Етап 1: Компіляція в .class

javac (для Java) або kotlinc (для Kotlin) компілюють вихідний код у .class файли. Кожен клас — окремий .class файл у Java-байткоді. На цьому етапі виконується перевірка типів, генерація bridge-методів та вбудовування констант.

Етап 2: D8 компіляція

D8 приймає всі .class файли та перетворює їх на DEX-байт-код. D8 виконує кілька оптимізацій: видаляє невикористовувані аргументи методів, об'єднує константні пули з різних .class в один глобальний пул DEX, конвертує стекові інструкції JVM у регістрові інструкції Dalvik.

kotlin
// Вихідний код Kotlin
data class User(
    val name: String,
    val email: String
)

fun greet(user: User): String {
    return "Hello, ${user.name}!"
}

Після компіляції D8 цей код перетворюється на компактні інструкції DEX: const-string для завантаження рядка, iget-object для доступу до поля об'єкта, invoke-virtual для виклику StringBuilder.append.

D8 vs DX

D8 працює швидше DX у 2–3 рази, генерує більш компактний DEX (на 5–10%) та краще оптимізує Kotlin-специфічні конструкції (inline функції, lambda). DX оголошено deprecated з 2018 року та видалено з Android Gradle Plugin 8.0.

Dalvik vs ART: як змінилося виконання DEX

Виконання DEX-коду в Android пройшло два етапи: оригінальна віртуальна машина Dalvik (Android 2.2–4.4) та Android Runtime ART (Android 5.0+). Різниця в підході до компіляції кардинальна.

Dalvik VM: JIT-компіляція

Dalvik використовувала Just-In-Time (JIT) компіляцію: DEX-байт-код інтерпретувався, а часто викликані методи компілювалися в нативний код на льоту. Плюс — швидке встановлення. Мінус — повільніший запуск та постійні витрати CPU на JIT.

ART: AOT-компіляція

ART (Android Runtime) компілює DEX у нативний код при встановленні додатку через dex2oat. Це Ahead-Of-Time (AOT) підхід: встановлення довше, але запуск швидший та споживання енергії менше. З Android 7.0 ART використовує гібридний підхід — AOT + JIT + Profile Guided Optimization.

dex2oat: конвертація при встановленні

Інструмент dex2oat запускається при встановленні або оновленні додатку. Він компілює DEX у ELF-файл з нативним кодом під архітектуру пристрою. Результат — файли .oat та .art у директорії /data/dalvik-cache/. Google постійно покращує dex2oat: на Android 14 додано оптимізацію для foldable-пристроїв.

Multidex: подолання ліміту 64K методів

Обмеження в 65536 методів на один DEX-файл — legacy від архітектури Dalvik. Поле method_ids у заголовку DEX займає 4 байти, що дає максимум 2^16 = 65536 унікальних посилань. Сучасні додатки з Google Play Services, Firebase та іншими SDK легко перевищують цей ліміт.

Механізм Multidex

Multidex — це механізм розділення коду на кілька DEX-файлів. Головний classes.dex містить точки входу (Application class, основні Activity), інші — classes2.dex, classes3.dex і так далі. При запуску класи з додаткових DEX завантажуються через DexClassLoader.

kotlin
// build.gradle.kts — включення multidex
android {
    defaultConfig {
        multiDexEnabled = true
    }
}

// Application клас з підтримкою multidex
class MyApp : Application() {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
        MultiDex.install(this)
    }
}

Проблеми Multidex

Завантаження додаткових DEX на етапі старту додатку може викликати ANR (Application Not Responding) на пристроях з Android до 5.0. Рекомендація — використовувати multidex тільки при необхідності та мінімізувати залежності, щоб не перевищувати ліміт.

Оптимізація DEX: ProGuard, R8 та обфускація

Оптимізація DEX — стандартний етап збірки релізного Android-додатку. Інструменти R8 та ProGuard зменшують розмір DEX, обфускують код та видаляють невикористовувані класи.

R8 vs ProGuard

R8 — наступник ProGuard, вбудований в Android Gradle Plugin з 2019 року. R8 виконує мініфікацію, обфускацію та оптимізацію за один прохід, тоді як ProGuard вимагав двох етапів: ProGuard → D8. ProGuard підтримується досі, але Google рекомендує R8 для нових проєктів.

R8 видаляє невикористовувані класи, методи та поля, перейменовує їх у короткі імена (a, b, c), вбудовує inline-функції та викидає dead-код. Результат — DEX зменшується на 20–40% без втрати функціональності.

Правила R8

Конфігурація R8 задається у файлі proguard-rules.pro. Розробник може вказати, які класи не можна перейменовувати (наприклад, для рефлексії або серіалізації Gson). Firebase та інші SDK постачають власні правила у своїх залежностях.

Декомпіляція DEX: інструменти та захист

DEX можна декомпілювати назад у Java-код. Це ключове питання безпеки Android-додатків: без обфускації код відновлюється до рівня, близького до вихідного.

Інструменти декомпіляції

JADX — найпопулярніший декомпілятор DEX у Java. Він відновлює імена класів, методи, поля та більшу частину логіки. apktool декомпілює DEX у smali-код (ассемблер Dalvik) — низькорівневе представлення, близьке до вихідних інструкцій. Bytecode Viewer об'єднує кілька декомпіляторів в одному інтерфейсі.

Методи захисту

Обфускація R8/ProGuard — перша лінія захисту: імена класів та методів стають нечитабельними. DexGuard — комерційний інструмент з додатковими методами: шифрування рядків, перевірка цілісності, анти-tamper. Обфускація на рівні Control Flow (O-LLVM) змінює структуру коду, зберігаючи його функціональність, але роблячи аналіз набагато складнішим.

Часто задавані питання

Чим DEX відрізняється від Java-байт-коду?

DEX використовує регістрову архітектуру замість стекової JVM, має більш компактний формат (на 30% менше), об'єднує всі .class в один файл з єдиним пулом констант та використовує 16-бітні індекси замість 8-бітних.

Що таке smali?

Smali — це асемблер DEX-байт-коду. Кожна інструкція DEX має текстове представлення у форматі smali. Інструмент baksmali конвертує DEX у smali (дизасемблювання), а smali збирає smali назад у DEX.

Як перевірити кількість методів у DEX?

Gradle task countMethods або плагін dex-method-counts показують кількість методів у кожному DEX-файлі. Команда adb shell з dumpsys також відображає статистику завантажених DEX для встановлених додатків.

Чи впливає кількість DEX на продуктивність?

Так, на пристроях до Android 8.0 багаторазовий DEX уповільнює запуск додатку, оскільки кожен додатковий файл завантажується окремо. На ART з Android 8.0+ різниця мінімальна завдяки компіляції dex2oat у єдиний .oat файл.

Чи можна запустити DEX без Android?

Так, існують проєкти, такі як dexplorer та Android-сумісні JVM-реалізації, які можуть виконувати DEX-байт-код поза Android. Однак більшість DEX-файлів використовують Android API, що робить їх непридатними для запуску на звичайній JVM.

Підсумки

  • DEX — формат байт-коду Android з регістровою архітектурою та компактним представленням коду.
  • Структура включає заголовок, таблиці ідентифікаторів та секцію даних з інструкціями.
  • Компіляція в DEX виконується через D8: .class → DEX з оптимізаціями та об'єднанням пулів констант.
  • ART компілює DEX у нативний код при встановленні (AOT), прискорюючи запуск додатку.
  • Multidex — вирішення проблеми ліміту 65536 методів через розділення на кілька DEX-файлів.
  • Оптимізація — R8 зменшує DEX на 20–40%, обфускує імена та видаляє мертвий код.
  • Захист — обфускація R8/ProGuard, DexGuard та O-LLVM запобігають декомпіляції DEX.

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

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

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

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