Android Runtime (ART) ได้รับการปรับปรุงอย่างมากใน Android 8.0 เวอร์ชันที่เปิดตัว รายการด้านล่างสรุปการเพิ่มประสิทธิภาพที่ผู้ผลิตอุปกรณ์จะได้รับ ใน ART
ตัวเก็บขยะแบบบีบอัดพร้อมกัน
ตามที่ได้ประกาศไปในงาน Google I/O ว่า ART มีตัวรวบรวมขยะ (GC) แบบพร้อมกันขนาดกะทัดรัดใหม่ใน Android 8.0 ตัวรวบรวมนี้จะบีบอัดฮีปทุกครั้งที่ GC ทำงานและขณะที่แอปทำงาน โดยจะหยุดชั่วคราวเพียงเล็กน้อยเพื่อประมวลผล รูทของเธรด ประโยชน์ของฟีเจอร์นี้มีดังนี้
- GC จะบีบอัดฮีปเสมอ โดยมีขนาดฮีปเล็กลงโดยเฉลี่ย 32% เมื่อเทียบกับ Android 7.0
- การบีบอัดช่วยให้การจัดสรรออบเจ็กต์ตัวชี้การเพิ่มแบบเฉพาะเธรดเป็นไปได้เร็วขึ้น โดยการจัดสรรจะเร็วขึ้น 70% เมื่อเทียบกับใน Android 7.0
- มีเวลาหยุดชั่วคราวที่สั้นลง 85% สำหรับการทดสอบ H2 เมื่อเทียบกับ GC ของ Android 7.0
- เวลาหยุดชั่วคราวจะไม่ปรับขนาดตามขนาดฮีปอีกต่อไป แอปควรใช้ฮีปขนาดใหญ่ได้โดยไม่ต้องกังวลเรื่องความกระตุก
- รายละเอียดการใช้งาน GC - Read barriers
- Read barriers คือปริมาณงานเล็กๆ ที่ทำสำหรับการอ่านฟิลด์ของแต่ละออบเจ็กต์
- ซึ่งได้รับการเพิ่มประสิทธิภาพในคอมไพเลอร์ แต่อาจทำให้บางกรณีการใช้งานช้าลง
การเพิ่มประสิทธิภาพลูป
ART ใช้การเพิ่มประสิทธิภาพลูปที่หลากหลายใน Android 8.0 รุ่นที่เผยแพร่
- การกำจัดการตรวจสอบขอบเขต
- แบบคงที่: ช่วงได้รับการพิสูจน์แล้วว่าอยู่ภายในขอบเขตที่เวลาคอมไพล์
- ไดนามิก: การทดสอบขณะรันไทม์ช่วยให้มั่นใจว่าลูปจะอยู่ในขอบเขต (ยกเลิกการเพิ่มประสิทธิภาพหากไม่เป็นเช่นนั้น)
- การกำจัดตัวแปรการเหนี่ยวนำ
- นำการเหนี่ยวนำที่หยุดทำงานออก
- แทนที่การเหนี่ยวนำที่ใช้หลังจากลูปเท่านั้นด้วยนิพจน์รูปแบบปิด
- การกำจัดโค้ดที่ไม่ได้ใช้ภายในส่วนเนื้อหาของลูป การนำลูปทั้งหมดที่ ไม่ได้ใช้แล้วออก
- การลดความแข็งแรง
- การแปลงลูป: การกลับด้าน การสลับ การแยก การคลาย การแปลงแบบยูนิโมดูลาร์ ฯลฯ
- SIMDization (หรือที่เรียกว่า Vectorization)
เครื่องมือเพิ่มประสิทธิภาพลูปจะอยู่ในการเพิ่มประสิทธิภาพของตัวเองในคอมไพเลอร์ ART การเพิ่มประสิทธิภาพลูปส่วนใหญ่จะคล้ายกับการเพิ่มประสิทธิภาพและการลดความซับซ้อน ในที่อื่นๆ ความท้าทายเกิดขึ้นกับการเพิ่มประสิทธิภาพบางอย่างที่เขียน CFG ใหม่ในลักษณะที่ซับซ้อนกว่าปกติ เนื่องจากเครื่องมือ CFG ส่วนใหญ่ (ดู nodes.h) มุ่งเน้นที่การสร้าง CFG ไม่ใช่การเขียนใหม่
การวิเคราะห์ลำดับชั้นของชั้นเรียน
ART ใน Android 8.0 ใช้การวิเคราะห์ลำดับชั้นของคลาส (CHA) ซึ่งเป็นการเพิ่มประสิทธิภาพคอมไพเลอร์ ที่เปลี่ยนการเรียกเสมือนเป็นการเรียกโดยตรงตามข้อมูล ที่สร้างขึ้นจากการวิเคราะห์ลำดับชั้นของคลาส การเรียกเสมือนมีค่าใช้จ่ายสูงเนื่องจาก มีการใช้งานการค้นหา vtable และต้องมีการโหลดที่ขึ้นต่อกัน 2 รายการ นอกจากนี้ การโทรเสมือนยังไม่สามารถแทรกในบรรทัดได้
สรุปการปรับปรุงที่เกี่ยวข้องมีดังนี้
- การอัปเดตสถานะของวิธีการติดตั้งใช้งานแบบครั้งเดียวแบบไดนามิก - เมื่อสิ้นสุดเวลาลิงก์ของคลาส เมื่อมีการป้อนข้อมูลลงใน vtable แล้ว ART จะทำการเปรียบเทียบรายการต่อรายการ กับ vtable ของคลาสซูเปอร์
- การเพิ่มประสิทธิภาพคอมไพเลอร์ - คอมไพเลอร์จะใช้ประโยชน์จาก ข้อมูลการติดตั้งใช้งานเดียวของเมธอด หากเมธอด A.foo มี ตั้งค่าแฟล็กการใช้งานเดียว คอมไพเลอร์จะเปลี่ยนการเรียกเสมือน เป็นการเรียกโดยตรง และพยายามแทรกการเรียกโดยตรงเป็นผลลัพธ์เพิ่มเติม
- การลบล้างโค้ดที่คอมไพล์แล้ว - เมื่อสิ้นสุดเวลาการลิงก์ชั้นเรียนด้วยเช่นกัน เมื่อมีการอัปเดตข้อมูลการใช้งานแบบเดี่ยว หากเมธอด A.foo ที่ก่อนหน้านี้มีการใช้งานแบบเดี่ยว แต่ตอนนี้สถานะดังกล่าวใช้ไม่ได้แล้ว โค้ดที่คอมไพล์แล้วทั้งหมดซึ่งขึ้นอยู่กับสมมติฐานที่ว่าเมธอด A.foo มีการใช้งานแบบเดี่ยวจะต้องลบล้างโค้ดที่คอมไพล์แล้ว
- การเพิ่มประสิทธิภาพ - สำหรับโค้ดที่คอมไพล์แบบสดซึ่งอยู่ในสแต็ก ระบบจะเริ่ม การเพิ่มประสิทธิภาพเพื่อบังคับให้โค้ดที่คอมไพล์แล้วซึ่งไม่ถูกต้องเข้าสู่โหมดอินเทอร์พรีเตอร์ เพื่อรับประกันความถูกต้อง ระบบจะใช้กลไกการเพิ่มประสิทธิภาพใหม่ซึ่งเป็นการผสมผสานระหว่าง การเพิ่มประสิทธิภาพแบบพร้อมกันและแบบไม่พร้อมกัน
แคชแบบอินไลน์ในไฟล์ .oat
ตอนนี้ ART ใช้แคชแบบอินไลน์และเพิ่มประสิทธิภาพเว็บไซต์ที่เรียกใช้ซึ่งมีข้อมูลเพียงพอ ฟีเจอร์แคชแบบอินไลน์จะบันทึกข้อมูลรันไทม์เพิ่มเติม ลงในโปรไฟล์และใช้เพื่อเพิ่มการเพิ่มประสิทธิภาพแบบไดนามิกลงในการคอมไพล์ล่วงหน้า
Dexlayout
Dexlayout เป็นไลบรารีที่เปิดตัวใน Android 8.0 เพื่อวิเคราะห์ไฟล์ dex และ จัดเรียงใหม่ตามโปรไฟล์ Dexlayout มีเป้าหมายที่จะใช้ข้อมูลการสร้างโปรไฟล์รันไทม์ เพื่อจัดเรียงส่วนต่างๆ ของไฟล์ DEX ใหม่ในระหว่างการบำรุงรักษาขณะไม่มีการใช้งาน การคอมไพล์ในอุปกรณ์ การจัดกลุ่มส่วนต่างๆ ของไฟล์ dex ที่มักมีการเข้าถึงร่วมกันจะช่วยให้โปรแกรมมีรูปแบบการเข้าถึงหน่วยความจำที่ดีขึ้นจากการปรับปรุงตำแหน่ง ซึ่งจะช่วยประหยัด RAM และลดเวลาเริ่มต้น
เนื่องจากขณะนี้ข้อมูลโปรไฟล์จะพร้อมใช้งานหลังจากที่แอปทำงานแล้วเท่านั้น จึงมีการผสานรวม dexlayout ไว้ในการคอมไพล์ในอุปกรณ์ของ dex2oat ระหว่างการบำรุงรักษาขณะที่ไม่มีการใช้งาน
การนำแคช Dex ออก
ใน Android 7.0 และเวอร์ชันก่อนหน้า ออบเจ็กต์ DexCache มีอาร์เรย์ขนาดใหญ่ 4 รายการ ซึ่งสอดคล้องกับ จำนวนองค์ประกอบบางอย่างใน DexFile ได้แก่
- สตริง (การอ้างอิง 1 รายการต่อ DexFile::StringId)
- types (การอ้างอิง 1 รายการต่อ DexFile::TypeId)
- methods (ตัวชี้ดั้งเดิม 1 รายการต่อ DexFile::MethodId)
- ฟิลด์ (ตัวชี้เนทีฟ 1 ตัวต่อ DexFile::FieldId)
อาร์เรย์เหล่านี้ใช้สำหรับการดึงข้อมูลออบเจ็กต์ที่เราแก้ไขก่อนหน้านี้อย่างรวดเร็ว ใน Android 8.0 ระบบได้นำอาร์เรย์ทั้งหมดออกแล้ว ยกเว้นอาร์เรย์เมธอด
ประสิทธิภาพของล่าม
ประสิทธิภาพของอินเทอร์พรีเตอร์ได้รับการปรับปรุงอย่างมากในรุ่น Android 7.0 ด้วยการเปิดตัว "mterp" ซึ่งเป็นอินเทอร์พรีเตอร์ที่มีกลไกการดึงข้อมูล/ถอดรหัส/ตีความหลักที่เขียนด้วยภาษาแอสเซมบลี Mterp สร้างขึ้นตามอินเทอร์พรีเตอร์ Dalvik ที่รวดเร็ว และรองรับ arm, arm64, x86, x86_64, mips และ mips64 สำหรับโค้ดการคำนวณ mterp ของ Art จะเทียบได้กับ อินเทอร์พรีเตอร์แบบเร็วของ Dalvik โดยประมาณ อย่างไรก็ตาม ในบางสถานการณ์ ความเร็วอาจช้าลงอย่างมาก
- เรียกใช้ประสิทธิภาพ
- การจัดการสตริงและผู้ใช้รายอื่นๆ ที่ใช้เมธอดที่ระบบรู้จักว่าเป็น Intrinsic ใน Dalvik อย่างหนัก
- การใช้งานหน่วยความจำสแต็กสูงขึ้น
Android 8.0 แก้ไขปัญหาเหล่านี้
การแทรกเพิ่มเติม
ตั้งแต่ Android 6.0 เป็นต้นมา ART สามารถแทรกการเรียกใดก็ได้ภายในไฟล์ dex เดียวกัน แต่จะแทรกได้เฉพาะเมธอดใบจากไฟล์ dex อื่นๆ เท่านั้น ข้อจำกัดนี้มีสาเหตุ 2 ประการ ดังนี้
- การแทรกจากไฟล์ DEX อื่นต้องใช้แคช DEX ของไฟล์ DEX อื่นนั้น ซึ่งต่างจากการแทรกไฟล์ DEX เดียวกันที่สามารถใช้แคช DEX ของผู้เรียกซ้ำได้ โค้ดที่คอมไพล์แล้วต้องใช้แคช dex สำหรับคำสั่งบางอย่าง เช่น การเรียกแบบคงที่ การโหลดสตริง หรือการโหลดคลาส
- แผนที่สแต็กจะเข้ารหัสเฉพาะดัชนีเมธอดภายในไฟล์ DEX ปัจจุบัน
Android 8.0 มีการเปลี่ยนแปลงต่อไปนี้เพื่อแก้ไขข้อจำกัดเหล่านี้
- นำสิทธิ์เข้าถึงแคช Dex ออกจากโค้ดที่คอมไพล์แล้ว (ดูส่วน "การนำแคช Dex ออก" ด้วย)
- ขยายการเข้ารหัสแผนที่สแต็ก
การปรับปรุงการซิงค์
ทีม ART ได้ปรับเส้นทางโค้ด MonitorEnter/MonitorExit และลดการพึ่งพาการแผงกั้นหน่วยความจำแบบเดิมใน ARMv8 โดยแทนที่ด้วยคำสั่งใหม่กว่า (acquire/release) เมื่อเป็นไปได้
วิธีการเนทีฟที่เร็วกว่า
การเรียกเนทีฟที่เร็วขึ้นไปยัง Java Native Interface (JNI) พร้อมใช้งานแล้วโดยใช้
คำอธิบายประกอบ @FastNative
และ @CriticalNative
การเพิ่มประสิทธิภาพรันไทม์ ART ในตัวเหล่านี้
จะช่วยเพิ่มความเร็วในการเปลี่ยน JNI และแทนที่สัญกรณ์ !bang JNI ที่เลิกใช้งานแล้ว
คำอธิบายประกอบจะไม่มีผลกับเมธอดที่ไม่ใช่เนทีฟ
และใช้ได้เฉพาะกับโค้ดภาษา Java ของแพลตฟอร์มใน
bootclasspath
(ไม่มีการอัปเดต Play Store)
คำอธิบายประกอบ @FastNative
รองรับเมธอดที่ไม่ใช่แบบคงที่ ใช้คำนี้
หากเมธอดเข้าถึง jobject
เป็นพารามิเตอร์หรือค่าที่ส่งคืน
คำอธิบายประกอบ @CriticalNative
ช่วยให้คุณเรียกใช้เมธอดเนทีฟได้รวดเร็วยิ่งขึ้น โดยมีข้อจำกัดดังนี้
-
เมธอดต้องเป็นแบบคงที่ โดยไม่มีออบเจ็กต์สำหรับพารามิเตอร์ ค่าที่ส่งคืน หรือ
this
โดยนัย - ระบบจะส่งเฉพาะประเภทดั้งเดิมไปยังเมธอดดั้งเดิม
-
เมธอดเนทีฟไม่ได้ใช้พารามิเตอร์
JNIEnv
และjclass
ในคำจำกัดความของฟังก์ชัน -
ต้องลงทะเบียนเมธอดกับ
RegisterNatives
แทนการ ใช้การลิงก์ JNI แบบไดนามิก
@FastNative
ช่วยปรับปรุงประสิทธิภาพของเมธอดเนทีฟได้สูงสุด 3 เท่า และ
@CriticalNative
ได้สูงสุด 5 เท่า เช่น การเปลี่ยน JNI ที่วัดได้
ในอุปกรณ์ Nexus 6P
การเรียกใช้ Java Native Interface (JNI) | เวลาดำเนินการ (หน่วยเป็นนาโนวินาที) |
---|---|
JNI ปกติ | 115 |
!bang JNI | 60 |
@FastNative |
35 |
@CriticalNative |
25 |