Android Runtime (ART) ได้รับการปรับปรุงอย่างมากในรุ่น Android 8.0 รายการด้านล่างสรุปการปรับปรุงที่ผู้ผลิตอุปกรณ์จะได้รับใน ART
Garbage Collector แบบการบีบอัดพร้อมกัน
ตามที่ได้ประกาศไปในงาน 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
- แถบการอ่านคืองานจำนวนเล็กน้อยที่ทําสําหรับการอ่านแต่ละช่องออบเจ็กต์
- ตัวแปรเหล่านี้ได้รับการเพิ่มประสิทธิภาพในคอมไพเลอร์ แต่อาจทําให้บางกรณีการใช้งานช้าลง
การเพิ่มประสิทธิภาพการวนซ้ำ
ART ใช้การเพิ่มประสิทธิภาพลูปที่หลากหลายในรุ่น Android 8.0 ดังนี้
- การยกเลิกการตรวจสอบขอบเขต
- แบบคงที่: ช่วงที่พิสูจน์แล้วว่าอยู่ภายในขอบเขตเมื่อคอมไพล์
- แบบไดนามิก: การทดสอบรันไทม์ช่วยให้มั่นใจว่าลูปจะอยู่ในขอบเขต (หากไม่ใช้ ให้เลือก "ปิดใช้")
- การนําตัวแปรอินดuction ออก
- นำอินดัคชันที่ตายแล้วออก
- แทนที่การอินดักชันที่ใช้หลังจากลูปเท่านั้นด้วยนิพจน์แบบปิด
- การกำจัดโค้ดที่ตายแล้วภายในตัวลูป การนำลูปทั้งลูปที่ตายแล้วออก
- การลดระดับ
- การเปลี่ยนรูปแบบของลูป: การกลับรายการ การสลับ แยก การเลิกม้วน การเปลี่ยนรูปแบบเป็นโมดูลเดียว ฯลฯ
- SIMDization (หรือที่เรียกว่า Vectorization)
เครื่องมือเพิ่มประสิทธิภาพของลูปจะอยู่ในรอบการเพิ่มประสิทธิภาพของตัวเองในคอมไพเลอร์ ART การเพิ่มประสิทธิภาพลูปส่วนใหญ่จะคล้ายกับการเพิ่มประสิทธิภาพและการลดความซับซ้อนในส่วนอื่นๆ ปัญหาเกิดขึ้นเมื่อการเพิ่มประสิทธิภาพบางอย่างเขียน CFG ใหม่ในลักษณะที่ซับซ้อนกว่าปกติ เนื่องจากยูทิลิตี CFG ส่วนใหญ่ (ดู nodes.h) มุ่งเน้นที่การสร้าง CFG ไม่ใช่การเขียนใหม่
การวิเคราะห์ลําดับชั้นของชั้นเรียน
ART ใน Android 8.0 ใช้การวิเคราะห์ลําดับชั้นของคลาส (CHA) ซึ่งเป็นการเพิ่มประสิทธิภาพคอมไพเลอร์ที่แปลงการเรียกเสมือนให้เป็นคําเรียกโดยตรงตามข้อมูลที่สร้างขึ้นจากการวิเคราะห์ลําดับชั้นของคลาส การเรียกเสมือนมีราคาแพงเนื่องจากมีการใช้งานกับการค้นหา vtable และต้องใช้การโหลดแบบมีเงื่อนไข 2 ครั้ง นอกจากนี้ คุณยังแทรกการโทรเสมือนในบรรทัดไม่ได้
สรุปการปรับปรุงที่เกี่ยวข้องมีดังนี้
- การอัปเดตสถานะเมธอดการใช้งานแบบไดนามิกรายการเดียว - เมื่อสิ้นสุดเวลาการลิงก์คลาสแล้ว เมื่อมีการป้อนข้อมูล vtable แล้ว ART จะทำการเปรียบเทียบทีละรายการกับ vtable ของคลาสหลัก
- การเพิ่มประสิทธิภาพคอมไพเลอร์ - คอมไพเลอร์จะใช้ประโยชน์จากข้อมูลการใช้งานแบบครั้งเดียวของเมธอด หากเมธอด A.foo มีการตั้งค่า Flag การใช้งานแบบเดี่ยว คอมไพเลอร์จะแปลงการเรียกเสมือนจริงเป็นการเรียกโดยตรง และพยายามแทรกการเรียกโดยตรงนั้นในบรรทัด
- โค้ดที่คอมไพล์แล้วใช้งานไม่ได้ - เมื่อถึงเวลาสิ้นสุดการลิงก์คลาสเมื่อมีการอัปเดตข้อมูลการใช้งานแบบครั้งเดียว หากเมธอด 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)
- ประเภท (การอ้างอิง 1 รายการต่อ DexFile::TypeId)
- วิธีการ (ตัวชี้เนทีฟ 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 อย่างไรก็ตาม ในบางสถานการณ์ ความเร็วในการค้นหาอาจช้าลงอย่างมาก
- เรียกใช้ประสิทธิภาพ
- การจัดการสตริง และผู้ใช้เมธอดอื่นๆ จำนวนมากที่ระบบจดจำว่าเป็นเมธอดภายในใน 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 |