DEX (Dalvik Executable) е форматът байткод, в който се компилира изходният код на Android приложения на Java и Kotlin. DEX файловете се изпълняват от виртуалната машина Dalvik (до Android 4.4) или Android Runtime (ART, от Android 5.0). Според данни на Android Open Source Project, 2026, форматът DEX осигурява средно 30% по-компактно представяне на кода в сравнение със стандартния JVM байткод.
Основни моменти
DEX (Dalvik Executable) е формат байткод, проектиран специално за мобилни устройства Android. За разлика от стандартния Java байткод (.class файлове), DEX е оптимизиран за ограничени ресурси: по-малко памет, по-малък размер и по-бързо зареждане на класове.
Изходният код на Java или Kotlin се компилира от javac/kotlinc в стандартни .class файлове (Java байткод). След това инструментът d8 (или по-рано dx) конвертира .class в един или няколко DEX файла. Тази конверсия не е просто преопаковане — d8 извършва оптимизации: обединява константни пулове, пренаписва инструкциите в регистрова архитектура и премахва дублирани данни.
DEX използва регистрова архитектура (за разлика от стековата JVM). Всеки метод има фиксиран брой регистри (до 65536). DEX инструкциите са по-къси — средно 2 байта срещу 1–4 байта в JVM. Това дава по-компактен код: типично приложение се намалява от 10–15 MB .class до 4–6 MB .dex.
DEX файлът има строго определена бинарна структура. Всеки файл започва със заглавка и съдържа няколко секции, които се препращат една към друга чрез отмествания.
| Секция | Предназначение |
|---|---|
| header | Заглавка: magic, контролна сума, подпис, размери и отмествания на секции |
| string_ids | Таблица с низове: имена на класове, методи, полета |
| type_ids | Типове: препратки към низови идентификатори на типове |
| proto_ids | Прототипи на методи: връщан тип и параметри |
| field_ids | Полета на класове: клас, тип, име |
| method_ids | Методи: клас, прототип, име |
| class_defs | Дефиниции на класове: флагове, superclass, интерфейси, отмествания на данни |
| data | Реални данни: код на методи, анотации, debug информация |
Магическото число на 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 работи 2–3 пъти по-бързо от DX, генерира по-компактен 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 байткодът се интерпретираше, а често извикваните методи се компилираха в native код в движение. Плюс — бързо инсталиране. Минус — по-бавно стартиране и постоянно CPU натоварване за JIT.
ART (Android Runtime) компилира DEX в native код при инсталиране на приложението чрез dex2oat. Това е Ahead-Of-Time (AOT) подход: инсталирането отнема повече време, но стартирането е по-бързо и консумацията на енергия е по-малка. От Android 7.0 ART използва хибриден подход — AOT + JIT + Profile Guided Optimization.
Инструментът dex2oat се стартира при инсталиране или обновяване на приложението. Той компилира DEX в ELF файл с native код за архитектурата на устройството. Резултат — .oat и .art файлове в директорията /data/dalvik-cache/. Google непрекъснато подобрява dex2oat: в Android 14 е добавена оптимизация за сгъваеми устройства.
Ограничението до 65536 метода на един DEX файл — наследство от архитектурата Dalvik. Полето method_ids в заглавката на DEX заема 4 байта, което дава максимум 2^16 = 65536 уникални препратки. Модерните приложения с Google Play Services, Firebase и други SDK лесно надвишават този лимит.
Multidex е механизъм за разделяне на кода на няколко DEX файла. Главният classes.dex съдържа входни точки (Application клас, основни Activity), останалите — classes2.dex, classes3.dex и така нататък. При стартиране класовете от допълнителните DEX се зареждат чрез DexClassLoader.
// build.gradle.kts — включване на multidex
android {
defaultConfig {
multiDexEnabled = true
}
}
// Application клас с поддръжка на 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 — стандартен етап от изграждането на release версия на Android приложение. Инструментите R8 и ProGuard намаляват размера на DEX, объркват кода и премахват неизползвани класове.
R8 — наследник на ProGuard, вграден в Android Gradle Plugin от 2019 г. R8 извършва минификация, объркване и оптимизация в едно преминаване, докато ProGuard изискваше два етапа: ProGuard → D8. ProGuard все още се поддържа, но Google препоръчва R8 за нови проекти.
R8 премахва неизползвани класове, методи и полета, преименува ги в кратки имена (a, b, c), вгражда inline функции и изхвърля мъртъв код. Резултат — 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. Объркването на ниво Control Flow (O-LLVM) променя структурата на кода, запазвайки функционалността му, но прави анализа много по-труден.
Често задавани въпроси
DEX използва регистрова архитектура вместо стековата JVM, има по-компактен формат (30% по-малък), обединява всички .class файлове в един файл с единен константен пул и използва 16-битови индекси вместо 8-битови.
Smali — асемблер на DEX байткода. Всяка DEX инструкция има текстово представяне в smali формат. Инструментът baksmali конвертира DEX в smali (дизасемблиране), а smali сглобява smali обратно в DEX.
Gradle задача 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също