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 ใช้พื้นที่น้อยกว่าไบต์โค้ด Java มาตรฐาน 30%
  • 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) จากนั้นเครื่องมือ d8 (หรือ dx ในอดีต) จะแปลง .class เป็นไฟล์ DEX หนึ่งไฟล์หรือมากกว่า การแปลงนี้ไม่ใช่แค่การบรรจุใหม่ — d8 ดำเนินการปรับแต่ง: รวมพูลค่าคงที่ เขียนคำสั่งใหม่เป็นสถาปัตยกรรมรีจิสเตอร์ และลบข้อมูลที่ซ้ำกัน

คุณสมบัติทางสถาปัตยกรรม

DEX ใช้สถาปัตยกรรม แบบรีจิสเตอร์ (ตรงกันข้ามกับ JVM แบบสแต็ก) แต่ละเมธอดมีจำนวนรีจิสเตอร์คงที่ (สูงสุด 65536) คำสั่ง DEX สั้นกว่า — เฉลี่ย 2 ไบต์เทียบกับ 1–4 ไบต์ใน JVM ซึ่งให้โค้ดที่กระชับกว่า: แอปพลิเคชันทั่วไปลดลงจาก 10–15 MB ของ .class เป็น 4–6 MB ของ .dex

โครงสร้างของไฟล์ DEX: ส่วนต่างๆ และส่วนหัว

ไฟล์ DEX มีโครงสร้างไบนารีที่กำหนดไว้อย่างเคร่งครัด แต่ละไฟล์เริ่มต้นด้วยส่วนหัวและประกอบด้วยหลายส่วนที่อ้างอิงถึงกันผ่านออฟเซ็ต

ส่วนวัตถุประสงค์
headerส่วนหัว: magic, checksum, ลายเซ็น, ขนาดและออฟเซ็ตของส่วนต่างๆ
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 ไบต์และประกอบด้วย checksum 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 ในขั้นตอนนี้ จะดำเนินการตรวจสอบชนิด การสร้างเมธอดบริดจ์ และการแทรกค่าคงที่

ขั้นตอนที่ 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 เทียบกับ DX

D8 ทำงานเร็วกว่า DX 2–3 เท่า สร้าง DEX ที่กระชับกว่า (เล็กกว่า 5–10%) และปรับแต่งโครงสร้างเฉพาะของ Kotlin ได้ดีกว่า (ฟังก์ชัน inline, lambda) DX ถูกประกาศว่าล้าสมัยในปี 2018 และถูกลบออกจาก Android Gradle Plugin 8.0

Dalvik เทียบกับ 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 เพิ่มการปรับแต่งสำหรับอุปกรณ์พับได้

Multidex: การเอาชนะขีดจำกัด 64K เมธอด

ขีดจำกัด 65536 เมธอดต่อไฟล์ DEX เป็นมรดกจากสถาปัตยกรรม Dalvik ฟิลด์ method_ids ในส่วนหัว DEX ใช้พื้นที่ 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
    }
}

// คลาส 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 เทียบกับ ProGuard

R8 เป็นผู้สืบทอดของ ProGuard ซึ่งรวมอยู่ใน Android Gradle Plugin ตั้งแต่ปี 2019 R8 ดำเนินการย่อขนาด การทำให้สับสน และการปรับแต่งในรอบเดียว ในขณะที่ ProGuard ต้องการสองขั้นตอน: ProGuard → D8 ProGuard ยังคงได้รับการสนับสนุน แต่ Google แนะนำ R8 สำหรับโปรเจกต์ใหม่

R8 ลบคลาส เมธอด และฟิลด์ที่ไม่ได้ใช้ เปลี่ยนชื่อเป็นชื่อสั้น (a, b, c) แทรกฟังก์ชัน inline และลบโค้ดที่ตายแล้ว ผลลัพธ์ — 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 เป็นเครื่องมือเชิงพาณิชย์ที่มีวิธีการเพิ่มเติม: การเข้ารหัสสตริง การตรวจสอบความสมบูรณ์ การป้องกันการดัดแปลง การทำให้สับสนโฟลว์ควบคุม (O-LLVM) เปลี่ยนโครงสร้างโค้ดในขณะที่รักษาฟังก์ชันการทำงาน ทำให้การวิเคราะห์ยากขึ้นมาก

คำถามที่พบบ่อย

DEX แตกต่างจากไบต์โค้ด Java อย่างไร?

DEX ใช้สถาปัตยกรรมแบบรีจิสเตอร์แทน JVM แบบสแต็ก มีรูปแบบที่กระชับกว่า (เล็กกว่า 30%) รวมไฟล์ .class ทั้งหมดเป็นไฟล์เดียวที่มีพูลค่าคงที่เดียว และใช้ดัชนี 16 บิตแทน 8 บิต

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 ทำให้การเริ่มต้นแอปพลิเคชันช้าลงเนื่องจากแต่ละไฟล์เพิ่มเติมถูกโหลดแยกกัน บน ART ที่มี Android 8.0+ ความแตกต่างน้อยมากเนื่องจากการคอมไพล์ dex2oat เป็นไฟล์ .oat เดียว

สามารถเรียกใช้ DEX โดยไม่มี Android ได้หรือไม่?

ได้ มีโปรเจกต์เช่น dexplorer และการใช้งาน JVM ที่เข้ากันได้กับ Android ที่สามารถดำเนินการไบต์โค้ด 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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม