DEX:バイトコードの構造と動作原理

著者: IT Sectr 公開日: 2026-04-15 読了時間: 8 分

DEX(Dalvik Executable)は、JavaおよびKotlinで記述されたAndroidアプリケーションのソースコードがコンパイルされるバイトコード形式です。DEXファイルは、Dalvik仮想マシン(Android 4.4まで)またはAndroid Runtime(ART、Android 5.0以降)によって実行されます。Android Open Source Project、2026によると、DEX形式は標準のJVM Javaバイトコードと比較して、平均30%よりコンパクトなコード表現を提供します。

重要なポイント

  • DEXはAndroid用のバイトコード形式で、DalvikまたはART上で実行されます。
  • コンパクト性 — DEXは標準Javaバイトコードよりも30%少ない容量です。
  • Multidex — 1つのDEXファイル内の65536メソッド制限を回避するメカニズム。
  • ART — Dalvikを置き換えたAndroid Runtimeは、インストール時にDEXをネイティブコードにコンパイルします。
  • D8 — 2018年からDXを置き換えた、Java/KotlinからDEXへの最新コンパイラ。

DEXとは何か、なぜ必要なのか

DEX(Dalvik Executable)は、Androidモバイルデバイス向けに特別に設計されたバイトコード形式です。標準的なJavaバイトコード(.classファイル)とは異なり、DEXは限られたリソース向けに最適化されています:メモリ消費が少なく、サイズが小さく、クラスロードが高速です。

JavaからDEXへ

JavaまたはKotlinのソースコードは、javac/kotlincによって標準の.classファイル(Javaバイトコード)にコンパイルされます。次に、d8ツール(または以前のdx)が.classを1つ以上のDEXファイルに変換します。この変換は単なる再パッケージ化ではなく、d8は最適化を実行します:定数プールの統合、レジスタアーキテクチャへの命令の書き換え、重複データの削除です。

アーキテクチャの特徴

DEXはレジスタベースのアーキテクチャを使用します(スタックベースのJVMとは異なります)。各メソッドは固定数のレジスタ(最大65536)を持ちます。DEX命令はより短く、平均2バイト(JVMでは1〜4バイト)です。これにより、よりコンパクトなコードが生成されます:典型的なアプリケーションは10〜15MBの.classから4〜6MBの.dexに縮小します。

DEXファイルの構造:セクションとヘッダー

DEXファイルは厳密に定義されたバイナリ構造を持ちます。各ファイルはヘッダーで始まり、互いにオフセットを介して参照し合う複数のセクションを含みます。

セクション目的
headerヘッダー:マジック、チェックサム、署名、セクションサイズとオフセット
string_ids文字列テーブル:クラス、メソッド、フィールド名
type_ids型:型文字列識別子への参照
proto_idsメソッドプロトタイプ:戻り値の型とパラメータ
field_idsクラスフィールド:クラス、型、名前
method_idsメソッド:クラス、プロトタイプ、名前
class_defsクラス定義:フラグ、スーパークラス、インターフェース、データオフセット
data実際のデータ:メソッドコード、アノテーション、デバッグ情報

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に1回だけ保存されます。dex2oatはARTコンパイル時にこれらのテーブルをさらに最適化します。

JavaとKotlinのDEXへのコンパイルプロセス

ソースコードをDEXに変換するプロセスは複数の段階からなります。最新のツールチェーンはD8コンパイラを使用し、2018年にAndroid Gradle Plugin 3.2でDXを置き換えました。

段階1:.classへのコンパイル

javac(Java用)またはkotlinc(Kotlin用)がソースコードを.classファイルにコンパイルします。各クラスはJavaバイトコードの個別の.classファイルです。この段階では、型チェック、ブリッジメソッドの生成、定数のインライン化が実行されます。

段階2:D8コンパイル

D8はすべての.classファイルを受け取り、DEXバイトコードに変換します。D8はいくつかの最適化を実行します:未使用のメソッド引数の削除、異なる.classファイルからの定数プールを1つのグローバル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、StringBuilder.append呼び出し用のinvoke-virtual。

D8 vs DX

D8はDXより2〜3倍高速で、よりコンパクトなDEX(5〜10%小さい)を生成し、Kotlin固有の構造(インライン関数、ラムダ)をより適切に最適化します。DXは2018年に非推奨が宣言され、Android Gradle Plugin 8.0で削除されました。

Dalvik vs ART:DEX実行の変化

AndroidでのDEXコードの実行は、2つの段階を経てきました:オリジナルのDalvik仮想マシン(Android 2.2〜4.4)とAndroid Runtime ART(Android 5.0+)です。コンパイルアプローチの違いは根本的です。

Dalvik VM:JITコンパイル

DalvikはJust-In-Time(JIT)コンパイルを使用していました:DEXバイトコードは解釈され、頻繁に呼び出されるメソッドはその場でネイティブコードにコンパイルされていました。利点 — インストールが高速。欠点 — 起動が遅く、JITによるCPU消費が常に発生。

ART:AOTコンパイル

ART(Android Runtime)は、dex2oatを介してアプリケーションインストール時にDEXをネイティブコードにコンパイルします。これはAhead-Of-Time(AOT)アプローチです:インストールは遅くなりますが、起動が速く、消費電力が低くなります。Android 7.0以降、ARTはハイブリッドアプローチを使用しています — AOT + JIT + プロファイルガイド最適化。

dex2oat:インストール時の変換

dex2oatツールはアプリケーションのインストール時または更新時に実行されます。DEXをデバイスアーキテクチャ向けのネイティブコードを含むELFファイルにコンパイルします。結果 — /data/dalvik-cache/ディレクトリ内の.oatおよび.artファイル。Googleは継続的にdex2oatを改善しています:Android 14では折りたたみデバイス向けの最適化が追加されました。

Multidex:64Kメソッド制限の克服

1つのDEXファイルあたり65536メソッドの制限は、Dalvikアーキテクチャの遺産です。DEXヘッダーのmethod_idsフィールドは4バイトを占め、最大2^16 = 65536の一意の参照を提供します。Google Play Services、Firebase、その他のSDKを使用する最新のアプリケーションは、簡単にこの制限を超えます。

Multidexの仕組み

Multidexは、コードを複数のDEXファイルに分割するメカニズムです。メインのclasses.dexにはエントリポイント(Applicationクラス、メインActivity)が含まれ、残りはclasses2.dex、classes3.dexなどとなります。起動時に、追加のDEXからのクラスはDexClassLoaderを介してロードされます。

kotlin
// build.gradle.kts — multidexの有効化
android {
    defaultConfig {
        multiDexEnabled = true
    }
}

// MultidexをサポートするApplicationクラス
class MyApp : Application() {
    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
        MultiDex.install(this)
    }
}

Multidexの問題

アプリケーション起動時の追加DEXのロードは、Android 5.0未満のデバイスでANR(Application Not Responding)を引き起こす可能性があります。推奨 — 必要な場合にのみmultidexを使用し、制限を超えないように依存関係を最小限に抑えます。

DEX最適化:ProGuard、R8と難読化

DEXの最適化は、リリース版Androidアプリケーションをビルドする際の標準的なステップです。R8およびProGuardツールはDEXサイズを削減し、コードを難読化し、未使用のクラスを削除します。

R8 vs ProGuard

R8はProGuardの後継であり、2019年からAndroid Gradle Pluginに組み込まれています。R8は単一パスで縮小化、難読化、最適化を実行しますが、ProGuardは2つの段階が必要でした:ProGuard → D8。ProGuardはまだサポートされていますが、Googleは新しいプロジェクトにはR8を推奨しています。

R8は未使用のクラス、メソッド、フィールドを削除し、それらを短い名前(a、b、c)に変更し、インライン関数を組み込み、デッドコードを除去します。結果 — 機能を損なうことなく、DEXが20〜40%削減されます。

R8ルール

R8の設定はproguard-rules.proファイルで指定されます。開発者は、リネームできないクラスを指定できます(例えば、リフレクションやGsonシリアライゼーション用)。Firebaseやその他のSDKは、依存関係に独自のルールを提供します。

DEX逆コンパイル:ツールと保護

DEXはJavaコードに逆コンパイルすることができます。これはAndroidアプリケーションの重要なセキュリティ問題です:難読化なしでは、コードはオリジナルに近いレベルに復元されます。

逆コンパイルツール

JADXは最も人気のあるDEXからJavaへの逆コンパイラです。クラス名、メソッド、フィールド、およびほとんどのロジックを復元します。apktoolはDEXをsmaliコード(Dalvikアセンブラ)に逆コンパイルします — 元の命令に近い低レベル表現です。Bytecode Viewerは複数の逆コンパイラを1つのインターフェースに統合します。

保護方法

R8/ProGuardによる難読化は防御の第一線です:クラス名とメソッド名が読み取り不能になります。DexGuardは追加の方法を備えた商用ツールです:文字列暗号化、整合性チェック、改ざん防止。制御フロー難読化(O-LLVM)は、機能を維持しながらコード構造を変更し、解析をはるかに困難にします。

よくある質問

DEXとJavaバイトコードの違いは?

DEXはスタックベースのJVMではなくレジスタベースのアーキテクチャを使用し、よりコンパクトな形式(30%小さい)で、すべての.classファイルを1つの定数プールを持つ1つのファイルに統合し、8ビットではなく16ビットのインデックスを使用します。

smaliとは?

SmaliはDEXバイトコードのアセンブラです。各DEX命令にはsmali形式のテキスト表現があります。baksmaliツールはDEXをsmaliに変換(逆アセンブル)し、smaliはsmaliをDEXにアセンブルします。

DEX内のメソッド数を確認する方法は?

GradleタスクcountMethodsまたはdex-method-countsプラグインは、各DEXファイル内のメソッド数を表示します。adb shellコマンドとdumpsysは、インストール済みアプリケーションのロードされたDEXの統計情報も表示します。

DEXファイルの数はパフォーマンスに影響しますか?

はい、Android 8.0未満のデバイスでは、複数のDEXファイルはアプリケーションの起動を遅くします。各追加ファイルが個別にロードされるためです。Android 8.0+のARTでは、dex2oatによる単一の.oatファイルへのコンパイルのおかげで、その差は最小限です。

AndroidなしでDEXを実行できますか?

はいdexplorerやAndroid互換JVM実装などのプロジェクトが存在し、Android外部でDEXバイトコードを実行できます。ただし、ほとんどのDEXファイルはAndroid APIを使用しているため、標準のJVMでの実行には適していません。

まとめ

  • DEXはレジスタベースのアーキテクチャとコンパクトなコード表現を持つAndroidバイトコード形式です。
  • 構造にはヘッダー、識別子テーブル、命令を含むデータセクションが含まれます。
  • コンパイルはD8を介してDEXに実行されます:.class → DEX(最適化と定数プール統合付き)。
  • ARTはインストール時にDEXをネイティブコード(AOT)にコンパイルし、アプリケーションの起動を高速化します。
  • Multidexは複数のDEXファイルに分割することで65536メソッド制限を解決します。
  • 最適化 — R8はDEXを20〜40%削減し、名前を難読化し、デッドコードを削除します。
  • 保護 — R8/ProGuard、DexGuard、O-LLVMによる難読化がDEX逆コンパイルを防ぎます。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください