การทำงานของ AOT/JIT Compiler บน Android N

Sittiphol Phanvilai
1 min readMar 24, 2016

Android N ใกล้จะปรากฎโฉม มีหลายอย่างที่เปลี่ยนแปลงไป แต่โดยรวมก็คือ Android M ที่สมบูรณ์ขึ้นนั่นแล

ในบรรดาหลายๆความเปลี่ยนแปลง อย่างนึงที่น่าสนใจคือการกลับมาของ JIT ก็เลยขอเอาเรื่องนี้มาเล่าลงในบล็อกนี้ครับ

เจาะอดีตกับ JIT

JIT (Just In Time) เป็นรูปแบบการทำงานของแอปแอนดรอยด์ในเวอร์ชันดั้งเดิมแต่ครั้งโบราณกาล เนื่องจากว่าแอปแอนดรอยด์ถูกเขียนมาด้วย Java เป็นหลัก ผลผลิตที่ได้จะได้ออกมาเป็น Bytecode ซึ่งรันเลยไม่ได้ ต้องถูกอ่านระหว่างทำงานแล้วแปลงเป็น Operation ไปรันต่ออีกทีนึง

แน่นอนว่าวิธีการทำงานแบบนั้นจะทำให้ประสิทธิภาพแย่ได้เนื่องจากต้องทำงานสองชั้น ตัว JIT เลยเกิดมาเพื่อแก้ปัญหานี้ด้วยการทำหน้าที่คอมไพล์ Bytecode ของโค้ดบริเวณที่ถูกเรียกใช้งานอยู่ให้กลายเป็น Executable Code ไว้ จากนั้นตอนรันโค้ดส่วนนั้นก็จะได้ไม่ต้องแปล Bytecode อีก จะรันกี่ทีก็ได้ก็จะได้ประสิทธิภาพที่ดีเยี่ยม

หากมีการย้ายตำแหน่งที่ทำงาน JIT ก็จะไปคอมไพล์โค้ดส่วนใหม่นั้นเก็บไว้และเป็นแบบนี้ไปเรื่อยๆ มันถึงเรียกว่า Just In Time เพราะมันทำงานบริเวณที่ถูกเรียกใช้งานเท่านั้น

ข้อเสียเล็กๆของมันคือมันต้องคอมไพล์ Bytecode แบบเรียลไทม์ไปเรื่อยๆจึงมี Overhead ตรงนี้นิดหน่อย จึงเกิดเป็นวิธีใหม่ที่ทำให้เรื่องตรงนี้ดีขึ้นอย่าง AOT

AOT — Ahead of Time

อย่าเพิ่งเข้าใจผิดว่าเป็นการท่าอากาศยาน AOT ก็ตรงตามความหมายเลย JIT มัน Just In Time ใช่มั้ย(ทำตอนนั้นเลย) ส่วน AOT คือ Ahead Of Time หรือการคอมไพล์ล่วงหน้ารอไว้เลยทั้งแอปนั่นเอง

แล้วถามว่าไปคอมไพล์ตอนไหน? คำตอบคือมันแอบคอมไพล์ตอนติดตั้งแอปเลยครับ เปลี่ยนจาก Bytecode เป็น Executable แบบ Native ตาม CPU Architecture นั้นๆได้เลย ประสิทธิภาพของการทำงานจึงทรงพลังมาก นอกจากนั้นเทคโนโลยีอีกหลายตัวก็ใช้เจ้า AOT ไปใช้ในการติดตั้งแอปแอนดรอยด์บน Hardware ต่างๆเช่น Wearable เพื่อประสิทธิภาพที่ดีขึ้น

ซึ่งเจ้าคอมไพเลอร์ตัวนี้จะพ่วงมากับ ART (Android Runtime) บน Android L จึงสามารถใช้ได้กับ Lollipop เป็นต้นไปเท่านั้นนั่นเอง

แต่แน่นอนว่าข้อเสียที่ต้องยอมทนคือ การติดตั้งแอปจะใช้เวลานานขึ้นมาก เพราะต้องคอมไพล์สดขณะติดตั้ง ถ้าแอปใหญ่นี่บางทีเป็นนาทีเลย ในขณะที่ JIT ไม่มีปัญหานี้เพราะก็อป Bytecode ลงตรงๆได้เลย ค่อยไปช้าตอนรันแทน

เจอกันครึ่งทาง การทำงานร่วมกันของ JIT และ AOT บน Android N

ปัญหาของการติดตั้งแอปช้าถือว่าเป็นปัญหาใหญ่มาก ยิ่งแอปใหญ่ก็ยิ่งติดตั้งนาน สุดท้ายจึงกลายเป็นข้อเสียที่ควรแก้ไข

แล้วจะแก้ยังไงดีหละ ในเมื่อ JIT ก็ทำงานช้า ต้องคอมไพล์เรื่อยๆ ส่วน AOT ก็ติดตั้งช้า …

งั้นเอางี้ ทำงานร่วมกันไปเลยละกัน !!

บน Android N ได้มีการเพิ่มส่วนของ JIT เข้ามาเพื่อทำงานร่วมกับ AOT ตามจังหวะที่เหมาะสมก็คือตอนติดตั้งจะลงเป็น Bytecode ไป ดังนั้นจะกลับไปติดตั้งแอปเร็วอีกครั้ง ตอนทำงานก็จะใช้ JIT ในการรันโค้ด

แล้วถ้ามีโค้ดส่วนไหนถูกเรียกใช้บ่อยมาก (เช่น Entry Point ของแอป) มันจะถูกคอมไพล์ด้วย AOT ไว้ และหากมีโค้ดส่วนไหนถูกเรียกใช้งานอีกมันก็จะจำและ Cache ไว้ (ข้อมูลยังไม่ชัด แต่ที่อ่านดูบางกรณีจะคอมไพล์ AOT เลย แต่บางกรณีจะเป็น JIT อยู่)

จากนั้นจะเป็นหน้าที่ระบบที่จะทยอยคอมไพล์โค้ดส่วนต่างๆเป็น AOT ให้โดยอิงกับการใช้งานแบตเตอรี่เป็นสำคัญ ก็คือจะคอมไพล์ให้ก็ต่อเมื่อเครื่องถูกชาร์จไว้ เป็นต้น แอปจะค่อยๆถูกเปลี่ยนเป็นส่วนๆไปเรื่อยๆจนครบ

ก็น่าจะพอมองเห็นภาพคร่าวๆของเจ้า AOT/JIT กันเรียบร้อยแล้วนะครับ ถือเป็นการเปลี่ยนแปลงที่น่าสนใจเลยแหละ เท่ดีนะ ตอนติดตั้งก็เร็ว แรกๆอาจจะทำงานไม่เร็วมากนัก(แต่สเปคเครื่องทุกวันนี้ก็แรงอยู่แล้ว ไม่ใช่ปัญหา) จากนั้นแอปจะทำงานได้ดีขึ้นเรื่อยๆตามเวลา

Reference: Android Developer

--

--

Sittiphol Phanvilai

A full-stack developer from Thailand. I use Medium mainly for the English article. My Thai blog posts are in https://nuuneoi.com by the way.