زمان اجرای Android (ART) در نسخه Android 8.0 بهطور قابلتوجهی بهبود یافته است. فهرست زیر بهبودهایی را که سازندگان دستگاه میتوانند در ART انتظار داشته باشند خلاصه میکند.
زبالهروب فشردهسازی همزمان
همانطور که در Google I/O اعلام شد، ART در Android 8.0 دارای ویژگی جدیدی است که بهطور همزمان زبالهها را جمعآوری میکند. این جمعآورنده هر بار که GC اجرا میشود و درحین اجرای برنامه، توده را فشرده میکند و فقط یک وقفه کوتاه برای پردازش ریشههای رشته دارد. مزایای آن در اینجا آورده شده است:
- «جمعآوری زباله» همیشه پشته را فشرده میکند: اندازه پشته بهطور میانگین ۳۲٪ کوچکتر از Android 7.0 است.
- فشردهسازی تخصیص شیء اشارهگر برآمدگی محلی رشته را فعال میکند: تخصیصها ٪۷۰ سریعتر از Android 7.0 است.
- در مقایسه با Android 7.0 GC، زمانهای توقف را برای معیار H2 تا ۸۵٪ کاهش میدهد.
- زمانهای توقف دیگر با اندازه پشته مقیاسبندی نمیشوند؛ برنامهها باید بتوانند از پشتههای بزرگ بدون نگرانی درباره لرزش استفاده کنند.
- جزئیات پیادهسازی GC - موانع خواندن:
- موانع خواندن مقدار کمی کار است که برای هر فیلد شیء خواندهشده انجام میشود.
- اینها در گردآورنده بهینهسازی میشوند، اما ممکن است برخیاز موارد استفاده را کند کنند.
بهینهسازیهای حلقه
طیف گستردهای از بهینهسازیهای حلقه توسط ART در نسخه Android 8.0 بهکار گرفته شده است:
- حذف بررسیهای مرز
- ایستا: در زمان ترجمه ثابت میشود که محدودهها در محدوده هستند
- پویا: آزمایشهای زمان اجرا تضمین میکند که حلقهها در محدوده باقی بمانند (درغیراینصورت بهینهسازیزدایی میشوند)
- حذف متغیر القایی
- برداشتن القای مرده
- جایگزین کردن القایی که فقط پساز حلقه با عبارتهای شکل بسته استفاده میشود
- حذف کد مرده در بدنه حلقه، حذف کل حلقههایی که مرده میشوند
- کاهش قدرت
- تبدیلهای حلقه: معکوس کردن، جابهجایی، تقسیم کردن، باز کردن، تکواحدی، و غیره.
- SIMDization (که برداریسازی نیز نامیده میشود)
بهینهساز حلقه در گذر بهینهسازی خود در کامپایلر ART قرار دارد. بیشتر بهینهسازیهای حلقه شبیه به بهینهسازیها و سادهسازیها در جاهای دیگر است. چالشها با برخیاز بهینهسازیهایی که CFG را به روشی پیچیدهتر از معمول بازنویسی میکنند، بهوجود میآیند، زیرا بیشتر ابزارهای CFG (به nodes.h مراجعه کنید) بر ساختن CFG تمرکز دارند، نه بازنویسی آن.
تجزیهوتحلیل سلسله مراتب کلاس
ART در Android 8.0 از «تجزیهوتحلیل سلسلهمراتب کلاس» (CHA)، بهینهسازی کامپایلر، استفاده میکند که براساس اطلاعات تولیدشده ازطریق تجزیهوتحلیل سلسلهمراتب کلاس، تماسهای مجازی را به تماسهای مستقیم تبدیل میکند. تماسهای مجازی گران هستند زیرا حول جستجوی جدول مجازی پیادهسازی میشوند و چند بارگیری وابسته انجام میدهند. همچنین تماسهای مجازی نمیتوانند درونخطی باشند.
خلاصهای از بهبودهای مرتبط در اینجا آمده است:
- بهروزرسانی وضعیت روش پیادهسازی تکی پویا - در پایان زمان پیونددهی کلاس، وقتی جدول مجازی پر شده باشد، ART مقایسهای ورودی به ورودی با جدول مجازی کلاس فرابَر انجام میدهد.
- بهینهسازی کامپایلر - کامپایلر از اطلاعات پیادهسازی واحد روش استفاده میکند. اگر روش A.foo پرچم تکپیادهسازی تنظیم شده باشد، ترجمهگر تماس مجازی را به تماس مستقیم غیرمجازیسازی میکند، و در ادامه سعی میکند تماس مستقیم را بهصورت درونخطی درآورد.
- باطل کردن کد کامپایلشده - همچنین در پایان زمان پیوند کلاس وقتی اطلاعات تکپیادهسازی بهروز میشود، اگر روش A.foo که قبلاً تکپیادهسازی داشت اما اکنون آن وضعیت باطل شده است، همه کدهای کامپایلشدهای که به این فرض وابسته هستند که روش A.foo تکپیادهسازی دارد باید کد کامپایلشدهشان باطل شود.
- Deoptimization - For live compiled code that's on stack, deoptimization will be initiated to force the invalidated compiled code into interpreter mode to guarantee correctness. از سازوکار جدیدی برای بهینهسازیزدایی استفاده خواهد شد که ترکیبی از بهینهسازیزدایی همزمان و ناهمزمان است.
حافظههای نهان بهخط در فایلهای .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 کاهش داد و آنها را با دستورالعملهای جدیدتر (کسب/انتشار) درصورت امکان جایگزین کرد.
روشهای بومی سریعتر
بااستفاده از حاشیهنویسیهای @FastNative و @CriticalNative، تماسهای بومی سریعتر با «میانای بومی جاوا» (JNI) دردسترس است. این بهینهسازیهای زمان اجرای ART داخلی
سرعت انتقالهای JNI را افزایش میدهند و جایگزین نمادگذاری
!bang JNI میشوند که اکنون منسوخ شده است. گزارمانها هیچ تأثیری بر روشهای غیربومی ندارند و فقط برای کد زبان Java پلاتفرم در bootclasspath دردسترس هستند (بدون بهروزرسانیهای «فروشگاه Play»).
حاشیهنویسی @FastNative از روشهای غیرایستا پشتیبانی میکند. اگر روشی به jobject بهعنوان پارامتر یا مقدار برگشتی دسترسی دارد، از این استفاده کنید.
حاشیهنویسی @CriticalNative روشی حتی سریعتر برای اجرای
روشهای بومی با محدودیتهای زیر ارائه میدهد:
-
روشها باید ایستا باشند—هیچ شیئی برای پارامترها، مقادیر برگشتی، یا
thisضمنی وجود ندارد. - فقط انواع اولیه به روش بومی منتقل میشوند.
-
روش بومی از پارامترهای
JNIEnvوjclassدر تعریف تابع خود استفاده نمیکند. -
این روش باید در
RegisterNativesثبت شود و به پیونددهی پویای JNI متکی نباشد.
@FastNative میتواند عملکرد روش بومی را تا ۳ برابر و
@CriticalNative را تا ۵ برابر بهبود دهد. برای مثال، گذار JNI اندازهگیریشده
در دستگاه Nexus 6P:
| فراخوانی «میانای بومی جاوا» (JNI) | زمان اجرا (به نانوثانیه) |
|---|---|
| JNI معمولی | 115 |
| !bang JNI | ۶۰ |
@FastNative |
35 |
@CriticalNative |
25 |