รันไทม์ของ Android (ART) ได้รับการปรับปรุงอย่างมีนัยสำคัญในการเปิดตัว Android 8.0 รายการด้านล่างสรุปการปรับปรุงที่ผู้ผลิตอุปกรณ์สามารถคาดหวังได้ใน ART
เครื่องรวบรวมขยะขนาดกะทัดรัดพร้อมกัน
ตามที่ประกาศที่ Google I/O ART นำเสนอเครื่องรวบรวมขยะขนาดกะทัดรัด (GC) พร้อมกันใหม่ใน Android 8.0 ตัวรวบรวมนี้จะบีบอัดฮีปทุกครั้งที่ GC รันและในขณะที่แอปกำลังทำงาน โดยหยุดชั่วคราวเพียงช่วงสั้นๆ เพียงครั้งเดียวเพื่อประมวลผลรูทของเธรด นี่คือคุณประโยชน์ของมัน:
- GC จะบีบอัดฮีปเสมอ: ขนาดฮีปเล็กลงโดยเฉลี่ย 32% เมื่อเทียบกับ Android 7.0
- การบดอัดช่วยให้สามารถจัดสรรวัตถุตัวชี้ชนภายในเธรด: การจัดสรรเร็วกว่าใน Android 7.0 ถึง 70%
- เสนอเวลาหยุดชั่วคราวน้อยลง 85% สำหรับการวัดประสิทธิภาพ H2 เมื่อเทียบกับ Android 7.0 GC
- เวลาหยุดชั่วคราวจะไม่ปรับขนาดตามขนาดฮีปอีกต่อไป แอพควรจะสามารถใช้ฮีปขนาดใหญ่ได้โดยไม่ต้องกังวลเรื่องปัญหาขยะ
- รายละเอียดการใช้งาน GC - อุปสรรคในการอ่าน:
- อุปสรรคในการอ่านคืองานเล็กๆ น้อยๆ ที่ทำขึ้นสำหรับการอ่านช่องอ็อบเจ็กต์แต่ละช่อง
- สิ่งเหล่านี้ได้รับการปรับให้เหมาะสมในคอมไพเลอร์ แต่อาจทำให้กรณีการใช้งานบางกรณีช้าลง
การเพิ่มประสิทธิภาพลูป
ART ใช้การเพิ่มประสิทธิภาพลูปที่หลากหลายในรุ่น Android 8.0:
- การกำจัดการตรวจสอบขอบเขต
- คงที่: ช่วงได้รับการพิสูจน์แล้วว่าอยู่ภายในขอบเขต ณ เวลาคอมไพล์
- ไดนามิก: การทดสอบรันไทม์ช่วยให้มั่นใจว่าลูปอยู่ภายในขอบเขต (มิฉะนั้นจะเลิกใช้)
- การกำจัดตัวแปรเหนี่ยวนำ
- ลบการเหนี่ยวนำที่ตายแล้ว
- แทนที่การเหนี่ยวนำที่ใช้หลังจากการวนซ้ำด้วยนิพจน์รูปแบบปิด
- การกำจัดโค้ดที่ไม่ทำงานภายในตัวลูป การลบลูปทั้งหมดที่กลายเป็นโค้ดที่ไม่ทำงาน
- ลดความแข็งแรง
- การแปลงแบบวนซ้ำ: การกลับตัว การสับเปลี่ยน การแยก การคลี่ การแยกส่วนเดียว ฯลฯ
- SIMDization (เรียกอีกอย่างว่า vectorization)
เครื่องมือเพิ่มประสิทธิภาพลูปอยู่ในผ่านการปรับให้เหมาะสมของตัวเองในคอมไพเลอร์ ART การปรับแต่งลูปให้เหมาะสมส่วนใหญ่จะคล้ายกับการปรับให้เหมาะสมและทำให้ง่ายขึ้นในที่อื่น ความท้าทายเกิดขึ้นกับการปรับให้เหมาะสมบางประการที่เขียน CFG ใหม่ด้วยวิธีที่ซับซ้อนมากกว่าปกติ เนื่องจากยูทิลิตี้ CFG ส่วนใหญ่ (ดู nodes.h) มุ่งเน้นไปที่การสร้าง CFG ไม่ใช่การเขียนใหม่
การวิเคราะห์ลำดับชั้นของชั้นเรียน
ART ใน Android 8.0 ใช้ Class Hierarchy Analysis (CHA) ซึ่งเป็นการเพิ่มประสิทธิภาพคอมไพเลอร์ที่จะแปลงการโทรเสมือนให้เป็นการโทรโดยตรงตามข้อมูลที่สร้างขึ้นโดยการวิเคราะห์ลำดับชั้นของคลาส การโทรเสมือนมีราคาแพงเนื่องจากมีการใช้งานกับการค้นหา vtable และต้องใช้โหลดที่ขึ้นต่อกันสองสามรายการ นอกจากนี้การโทรเสมือนไม่สามารถอินไลน์ได้
นี่คือบทสรุปของการปรับปรุงที่เกี่ยวข้อง:
- การอัปเดตสถานะวิธีการปรับใช้ครั้งเดียวแบบไดนามิก - เมื่อสิ้นสุดเวลาการเชื่อมโยงคลาส เมื่อมีการเติม 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 เป็นเจ้าของอาร์เรย์ขนาดใหญ่สี่ชุด ซึ่งสัดส่วนกับจำนวนขององค์ประกอบบางอย่างใน DexFile กล่าวคือ:
- สตริง (หนึ่งการอ้างอิงต่อ DexFile::StringId)
- ประเภท (หนึ่งการอ้างอิงต่อ DexFile::TypeId)
- วิธีการ (หนึ่งตัวชี้ดั้งเดิมต่อ DexFile::MethodId)
- (หนึ่งตัวชี้เนทิฟต่อ 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 ที่แตกต่างกันเท่านั้น มีเหตุผลสองประการสำหรับข้อจำกัดนี้:
- การอินไลน์จากไฟล์ dex อื่นจำเป็นต้องใช้แคช dex ของไฟล์ dex อื่นนั้น ซึ่งแตกต่างจากการอินไลน์ไฟล์ dex เดียวกัน ซึ่งสามารถนำแคช dex ของผู้เรียกกลับมาใช้ใหม่ได้ จำเป็นต้องใช้แคช dex ในโค้ดที่คอมไพล์สำหรับคำสั่งสองสามอย่าง เช่น การเรียกแบบคงที่ โหลดสตริง หรือโหลดคลาส
- แผนที่สแต็กกำลังเข้ารหัสดัชนีวิธีการภายในไฟล์ dex ปัจจุบันเท่านั้น
เพื่อแก้ไขข้อจำกัดเหล่านี้ Android 8.0:
- ลบการเข้าถึงแคช dex ออกจากโค้ดที่คอมไพล์แล้ว (ดูหัวข้อ "การลบแคช Dex")
- ขยายการเข้ารหัสแผนที่สแต็ก
การปรับปรุงการซิงโครไนซ์
ทีม ART ปรับเส้นทางโค้ด MonitorEnter/MonitorExit และลดการพึ่งพาอุปสรรคหน่วยความจำแบบเดิมบน ARMv8 โดยแทนที่ด้วยคำแนะนำที่ใหม่กว่า (รับ/ปล่อย) เมื่อเป็นไปได้
วิธีการดั้งเดิมที่เร็วขึ้น
การเรียกเนทิฟที่เร็วขึ้นไปยัง 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) | เวลาดำเนินการ (เป็นนาโนวินาที) |
---|---|
เจเอ็นไอประจำ | 115 |
!ปัง JNI | 60 |
@FastNative | 35 |
@CriticalNative | 25 |