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 (Dalvik Executable) — это формат байт-кода, разработанный специально для мобильных устройств Android. В отличие от стандартного Java-байт-кода (.class файлы), 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 имеет строго определённую бинарную структуру. Каждый файл начинается с заголовка и содержит несколько секций, которые ссылаются друг на друга через смещения.
| Секция | Назначение |
|---|---|
| header | Заголовок: magic, контрольная сумма, подпись, размеры и смещения секций |
| string_ids | Таблица строк: имена классов, методов, полей |
| type_ids | Типы: ссылки на строковые идентификаторы типов |
| proto_ids | Прототипы методов: возвращаемый тип и параметры |
| field_ids | Поля классов: класс, тип, имя |
| method_ids | Методы: класс, прототип, имя |
| class_defs | Определения классов: флаги, superclass, interfaces, смещения данных |
| data | Фактические данные: код методов, аннотации, debug info |
Магическое число 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 дополнительно оптимизирует эти таблицы.
Процесс превращения исходного кода в DEX состоит из нескольких этапов. Современная цепочка использует компилятор D8, который пришёл на смену DX в 2018 году с Android Gradle Plugin 3.2.
javac (для Java) или kotlinc (для Kotlin) компилируют исходный код в .class файлы. Каждый класс — отдельный .class файл в Java-байткоде. На этом этапе выполняется проверка типов, генерация bridge-методов и встраивание констант.
D8 принимает все .class файлы и преобразует их в DEX-байт-код. D8 выполняет несколько оптимизаций: удаляет неиспользуемые аргументы методов, объединяет константные пулы из разных .class в один глобальный пул DEX, конвертирует стековые инструкции JVM в регистровые инструкции Dalvik.
// Исходный код 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 работает быстрее DX в 2–3 раза, генерирует более компактный DEX (на 5–10%) и лучше оптимизирует Kotlin-специфичные конструкции (inline функции, lambda). DX объявлен deprecated с 2018 года и удалён из Android Gradle Plugin 8.0.
Исполнение DEX-кода в Android прошло два этапа: оригинальная виртуальная машина Dalvik (Android 2.2–4.4) и Android Runtime ART (Android 5.0+). Разница в подходе к компиляции кардинальная.
Dalvik использовала Just-In-Time (JIT) компиляцию: DEX-байт-код интерпретировался, а часто вызываемые методы компилировались в нативный код на лету. Плюс — быстрая установка. Минус — более медленный запуск и постоянные затраты CPU на JIT.
ART (Android Runtime) компилирует DEX в нативный код при установке приложения через dex2oat. Это Ahead-Of-Time (AOT) подход: установка дольше, но запуск быстрее и потребление энергии меньше. С Android 7.0 ART использует гибридный подход — AOT + JIT + Profile Guided Optimization.
Инструмент dex2oat запускается при установке или обновлении приложения. Он компилирует DEX в ELF-файл с нативным кодом под архитектуру устройства. Результат — файлы .oat и .art в директории /data/dalvik-cache/. Google постоянно улучшает dex2oat: на Android 14 добавлена оптимизация для foldable-устройств.
Ограничение в 65536 методов на один DEX-файл — legacy от архитектуры Dalvik. Поле method_ids в заголовке DEX занимает 4 байта, что даёт максимум 2^16 = 65536 уникальных ссылок. Современные приложения с Google Play Services, Firebase и другими SDK легко превышают этот лимит.
Multidex — это механизм разделения кода на несколько DEX-файлов. Главный classes.dex содержит точки входа (Application class, основные Activity), остальные — classes2.dex, classes3.dex и так далее. При запуске классы из дополнительных DEX загружаются через DexClassLoader.
// build.gradle.kts — включение multidex
android {
defaultConfig {
multiDexEnabled = true
}
}
// Application class с поддержкой multidex
class MyApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
Загрузка дополнительных DEX на этапе старта приложения может вызывать ANR (Application Not Responding) на устройствах с Android до 5.0. Рекомендация — использовать multidex только при необходимости и минимизировать зависимости, чтобы не превышать лимит.
Оптимизация DEX — стандартный этап сборки релизного Android-приложения. Инструменты R8 и ProGuard уменьшают размер DEX, обфусцируют код и удаляют неиспользуемые классы.
R8 — преемник ProGuard, встроенный в Android Gradle Plugin с 2019 года. R8 выполняет минификацию, обфускацию и оптимизацию за один проход, тогда как ProGuard требовал двух этапов: ProGuard → D8. ProGuard поддерживается до сих пор, но Google рекомендует R8 для новых проектов.
R8 удаляет неиспользуемые классы, методы и поля, переименовывает их в короткие имена (a, b, c), встраивает inline-функции и выбрасывает dead-код. Результат — DEX уменьшается на 20–40% без потери функциональности.
Конфигурация R8 задаётся в файле proguard-rules.pro. Разработчик может указать, какие классы нельзя переименовывать (например, для рефлексии или сериализации Gson). Firebase и другие SDK поставляют собственные правила в своих зависимостях.
DEX можно декомпилировать обратно в Java-код. Это ключевой вопрос безопасности Android-приложений: без обфускации код восстанавливается до уровня, близкого к исходному.
JADX — самый популярный декомпилятор DEX в Java. Он восстанавливает имена классов, методы, поля и большую часть логики. apktool декомпилирует DEX в smali-код (ассемблер Dalvik) — низкоуровневое представление, близкое к исходным инструкциям. Bytecode Viewer объединяет несколько декомпиляторов в одном интерфейсе.
Обфускация R8/ProGuard — первая линия защиты: имена классов и методов становятся нечитаемыми. DexGuard — коммерческий инструмент с дополнительными методами: шифрование строк, проверка целостности, анти-tamper. Obfuscation на уровне Control Flow (O-LLVM) изменяет структуру кода, сохраняя его функциональность, но делая анализ намного сложнее.
Часто задаваемые вопросы
DEX использует регистровую архитектуру вместо стековой JVM, имеет более компактный формат (на 30% меньше), объединяет все .class в один файл с единым пулом констант и использует 16-битные индексы вместо 8-битных.
Smali — это ассемблер DEX-байт-кода. Каждая инструкция DEX имеет текстовое представление в формате smali. Инструмент baksmali конвертирует DEX в smali (дизассемблирование), а smali собирает smali обратно в DEX.
Gradle task countMethods или плагин dex-method-counts показывают количество методов в каждом DEX-файле. Команда adb shell с dumpsys также отображает статистику загруженных DEX для установленных приложений.
Да, на устройствах до Android 8.0 многократный DEX замедляет запуск приложения, так как каждый дополнительный файл загружается отдельно. На ART с Android 8.0+ разница минимальна благодаря компиляции dex2oat в единый .oat файл.
Да, существуют проекты, такие как dexplorer и Android-совместимые JVM-реализации, которые могут исполнять DEX-байт-код вне Android. Однако большинство DEX-файлов используют Android API, что делает их непригодными для запуска на обычной JVM.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также