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) จากนั้นเครื่องมือ d8 (หรือ dx ในอดีต) จะแปลง .class เป็นไฟล์ DEX หนึ่งไฟล์หรือมากกว่า การแปลงนี้ไม่ใช่แค่การบรรจุใหม่ — d8 ดำเนินการปรับแต่ง: รวมพูลค่าคงที่ เขียนคำสั่งใหม่เป็นสถาปัตยกรรมรีจิสเตอร์ และลบข้อมูลที่ซ้ำกัน
DEX ใช้สถาปัตยกรรม แบบรีจิสเตอร์ (ตรงกันข้ามกับ JVM แบบสแต็ก) แต่ละเมธอดมีจำนวนรีจิสเตอร์คงที่ (สูงสุด 65536) คำสั่ง DEX สั้นกว่า — เฉลี่ย 2 ไบต์เทียบกับ 1–4 ไบต์ใน JVM ซึ่งให้โค้ดที่กระชับกว่า: แอปพลิเคชันทั่วไปลดลงจาก 10–15 MB ของ .class เป็น 4–6 MB ของ .dex
ไฟล์ DEX มีโครงสร้างไบนารีที่กำหนดไว้อย่างเคร่งครัด แต่ละไฟล์เริ่มต้นด้วยส่วนหัวและประกอบด้วยหลายส่วนที่อ้างอิงถึงกันผ่านออฟเซ็ต
| ส่วน | วัตถุประสงค์ |
|---|---|
| header | ส่วนหัว: magic, checksum, ลายเซ็น, ขนาดและออฟเซ็ตของส่วนต่างๆ |
| string_ids | ตารางสตริง: ชื่อคลาส เมธอด ฟิลด์ |
| type_ids | ชนิด: การอ้างอิงถึงตัวระบุสตริงของชนิด |
| proto_ids | ต้นแบบเมธอด: ชนิดที่ส่งคืนและพารามิเตอร์ |
| field_ids | ฟิลด์ของคลาส: คลาส ชนิด ชื่อ |
| method_ids | เมธอด: คลาส ต้นแบบ ชื่อ |
| class_defs | คำจำกัดความของคลาส: แฟล็ก ซูเปอร์คลาส อินเทอร์เฟซ ออฟเซ็ตข้อมูล |
| data | ข้อมูลจริง: โค้ดเมธอด คำอธิบายประกอบ ข้อมูลดีบัก |
เลข มหัศจรรย์ ของ 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
กระบวนการ แปลงซอร์สโค้ดเป็น DEX ประกอบด้วยหลายขั้นตอน ห่วงโซ่เครื่องมือสมัยใหม่ใช้คอมไพเลอร์ D8 ซึ่งแทนที่ DX ในปี 2018 ด้วย Android Gradle Plugin 3.2
javac (สำหรับ Java) หรือ kotlinc (สำหรับ Kotlin) คอมไพล์ซอร์สโค้ดเป็นไฟล์ .class แต่ละคลาสคือไฟล์ .class แยกต่างหากในไบต์โค้ด Java ในขั้นตอนนี้ จะดำเนินการตรวจสอบชนิด การสร้างเมธอดบริดจ์ และการแทรกค่าคงที่
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 ถูกประกาศว่าล้าสมัยในปี 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 เพิ่มการปรับแต่งสำหรับอุปกรณ์พับได้
ขีดจำกัด 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 เป็นขั้นตอนมาตรฐานในการสร้างแอปพลิเคชัน 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 เป็นเครื่องมือเชิงพาณิชย์ที่มีวิธีการเพิ่มเติม: การเข้ารหัสสตริง การตรวจสอบความสมบูรณ์ การป้องกันการดัดแปลง การทำให้สับสนโฟลว์ควบคุม (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 และการใช้งาน JVM ที่เข้ากันได้กับ Android ที่สามารถดำเนินการไบต์โค้ด DEX นอก Android ได้ อย่างไรก็ตาม ไฟล์ DEX ส่วนใหญ่ใช้ Android API ซึ่งทำให้ไม่เหมาะสมสำหรับการทำงานบน JVM มาตรฐาน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ