تم تحسين وقت تشغيل Android (ART) بشكل كبير في إصدار Android 8.0. يلخّص الجدول أدناه التحسينات التي يمكن أن يتوقّعها مصنّعو الأجهزة في ART.
أداة جمع البيانات المهملة المتزامنة
كما تم الإعلان في مؤتمر Google I/O، يتضمّن ART أداة جديدة لجمع البيانات غير المرغوب فيها بشكل متزامن ومضغوط في نظام التشغيل Android 8.0. تعمل أداة التجميع هذه على ضغط الذاكرة المؤقتة كلما تم تشغيل عملية جمع البيانات المهملة وأثناء تشغيل التطبيق، مع إيقاف مؤقت قصير واحد فقط لمعالجة جذور سلسلة المحادثات. في ما يلي مزاياه:
- تعمل عملية جمع البيانات غير الضرورية دائمًا على ضغط الذاكرة المؤقتة: أحجام الذاكرة المؤقتة أصغر بنسبة% 32 في المتوسط مقارنةً بنظام التشغيل Android 7.0.
- تتيح عملية الضغط تخصيص كائنات مؤشر الارتفاع المحلية للعمليات: عمليات التخصيص أسرع بنسبة% 70 من الإصدار 7.0 من نظام التشغيل Android.
- توفّر أوقات توقّف مؤقت أصغر بنسبة% 85 في معيار H2 مقارنةً ببرنامج تجميع البيانات غير المرغوب فيها في Android 7.0.
- لم تعُد أوقات الإيقاف المؤقت تتناسب مع حجم الذاكرة المؤقتة، ويجب أن تتمكّن التطبيقات من استخدام الذاكرات المؤقتة الكبيرة بدون القلق بشأن حدوث تشوّش.
- تفاصيل تنفيذ عملية جمع البيانات المهملة - حواجز القراءة:
- حواجز القراءة هي مقدار صغير من العمل يتم تنفيذه لكل حقل كائن تتم قراءته.
- يتم تحسين هذه الحالات في المترجم، ولكن قد تؤدي إلى إبطاء بعض حالات الاستخدام.
تحسينات الحلقات
تستخدم ART مجموعة متنوعة من عمليات تحسين الحلقات في إصدار Android 8.0:
- إزالة عمليات التحقّق من الحدود
- ثابتة: يتم إثبات أنّ النطاقات ضمن الحدود في وقت الترجمة البرمجية
- ديناميكي: تضمن الاختبارات أثناء وقت التشغيل بقاء الحلقات ضمن الحدود (وإلا سيتم إلغاء التحسين)
- إزالة متغيرات الاستقراء
- إزالة الاستقراء غير الصحيح
- استبدال الاستقراء الذي يتم استخدامه فقط بعد الحلقة بتعبيرات ذات صيغة مغلقة
- إزالة الرمز البرمجي غير المستخدَم داخل نص الحلقة، وإزالة الحلقات الكاملة التي تصبح غير مستخدَمة
- تقليل قوة التشفير
- تحويلات الحلقات: العكس، والتبديل، والتقسيم، والتوسيع، والوحدة، وما إلى ذلك
- تحويل التعليمات إلى متجهات (يُعرف أيضًا باسم SIMDization)
يقع محسِّن الحلقات في مرحلة التحسين الخاصة به في برنامج ART المجمّع. معظم عمليات تحسين الحلقات تشبه عمليات التحسين والتبسيط في أماكن أخرى. تظهر تحديات مع بعض عمليات التحسين التي تعيد كتابة CFG بطريقة أكثر تفصيلاً من المعتاد، لأنّ معظم أدوات CFG (راجِع nodes.h) تركّز على إنشاء CFG، وليس إعادة كتابتها.
تحليل التسلسل الهرمي للفئات
يستخدم ART في Android 8.0 ميزة "تحليل التسلسل الهرمي للفئات" (CHA)، وهي عملية تحسين للمترجم البرمجي تعمل على تحويل المكالمات الافتراضية إلى مكالمات مباشرة استنادًا إلى المعلومات التي يتم إنشاؤها من خلال تحليل التسلسلات الهرمية للفئات. المكالمات الافتراضية مكلفة لأنّها تعتمد على البحث في جدول الدوال الافتراضية، وتتطلّب تنفيذ بعض عمليات التحميل المتعلّقة ببعضها. لا يمكن أيضًا تضمين المكالمات الافتراضية.
في ما يلي ملخّص للتحسينات ذات الصلة:
- تعديل حالة طريقة التنفيذ الفردي الديناميكي - في نهاية وقت ربط الفئة، عندما تتم تعبئة جدول الدوال الافتراضية، يجري ART مقارنة بين كل إدخال في جدول الدوال الافتراضية وبين جدول الدوال الافتراضية للفئة الرئيسية.
- تحسين المترجم البرمجي: سيستفيد المترجم البرمجي من معلومات التنفيذ الفردي لإحدى الطرق. إذا تم ضبط علامة التنفيذ الفردي للطريقة A.foo، سيزيل المترجم وظيفة التوافق مع الإصدارات السابقة للمكالمة الافتراضية ويحوّلها إلى مكالمة مباشرة، ثم سيحاول تضمين المكالمة المباشرة كنتيجة لذلك.
- إبطال صحة الرمز البرمجي الذي تم تجميعه: يحدث ذلك أيضًا في نهاية وقت ربط الفئة عند تعديل معلومات التنفيذ الفردي. إذا كان الإجراء A.foo يتضمّن تنفيذًا فرديًا في السابق ولكن تم إبطال هذه الحالة الآن، يجب إبطال صحة جميع الرموز البرمجية التي تم تجميعها والتي تعتمد على افتراض أنّ الإجراء A.foo يتضمّن تنفيذًا فرديًا.
- إلغاء التحسين: بالنسبة إلى الرمز البرمجي الذي تم تجميعه مباشرةً والموجود في الذاكرة، سيتم بدء عملية إلغاء التحسين لإجبار الرمز البرمجي الذي تم تجميعه والذي تم إبطاله على الانتقال إلى وضع المفسّر لضمان صحته. سيتم استخدام آلية جديدة لإزالة التحسينات، وهي آلية مختلطة بين إزالة التحسينات المتزامنة وغير المتزامنة.
ذاكرات التخزين المؤقت المضمّنة في ملفات .oat
يستخدم ART الآن ذاكرات تخزين مؤقت مضمّنة ويحسّن مواقع الاتصال التي تتوفّر لها بيانات كافية. تسجّل ميزة "التخزين المؤقت المضمّن" معلومات إضافية عن وقت التشغيل في الملفات الشخصية، وتستخدمها لإضافة تحسينات ديناميكية إلى عملية الترجمة المسبقة.
Dexlayout
Dexlayout هي مكتبة تم طرحها في الإصدار 8.0 من نظام التشغيل Android لتحليل ملفات dex وإعادة ترتيبها وفقًا لأحد الملفات الشخصية. تهدف Dexlayout إلى استخدام معلومات تحديد الأداء في وقت التشغيل لإعادة ترتيب أقسام ملف dex أثناء عملية الصيانة في وضع عدم النشاط، وذلك عند تجميع التطبيق على الجهاز. من خلال تجميع أجزاء من ملف dex التي يتم الوصول إليها غالبًا معًا، يمكن أن يكون للبرامج أنماط أفضل للوصول إلى الذاكرة من خلال تحسين الموضع، ما يؤدي إلى توفير ذاكرة الوصول العشوائي وتقليل وقت بدء التشغيل.
بما أنّ معلومات الملف الشخصي لا تتوفّر حاليًا إلا بعد تشغيل التطبيقات، يتم دمج dexlayout في عملية تجميع dex2oat على الجهاز أثناء الصيانة في وضع عدم النشاط.
إزالة ذاكرة التخزين المؤقت لملفات Dex
حتى الإصدار 7.0 من نظام التشغيل Android، كان كائن 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
- استخدام أكبر لذاكرة التخزين المؤقت
يعالج الإصدار 8.0 من نظام التشغيل Android هذه المشاكل.
المزيد من التضمين
منذ الإصدار 6.0 من نظام التشغيل Android، يمكن لـ ART تضمين أي عملية استدعاء ضمن ملفات dex نفسها، ولكن كان بإمكانه تضمين طرق الأوراق فقط من ملفات dex مختلفة. كان هناك سببان لهذا القيد:
- يتطلّب التضمين من ملف dex آخر استخدام ذاكرة التخزين المؤقت لملف dex الآخر، على عكس التضمين من ملف dex نفسه، والذي يمكنه إعادة استخدام ذاكرة التخزين المؤقت لملف dex الخاص بالدالة المستدعِية. مطلوب استخدام ذاكرة التخزين المؤقت dex في الرمز البرمجي المترجَم لبعض التعليمات، مثل عمليات الاستدعاء الثابتة أو تحميل السلسلة أو تحميل الفئة.
- لا ترمّز خرائط حزمة البيانات سوى فهرس طريقة ضمن ملف dex الحالي.
لحلّ هذه المشاكل، يوفّر نظام التشغيل Android 8.0 ما يلي:
- إزالة إذن الوصول إلى ذاكرة التخزين المؤقت لملفات dex من الرمز البرمجي الذي تم تجميعه (راجِع أيضًا القسم "إزالة ذاكرة التخزين المؤقت لملفات dex")
- توسّع هذه السمة ترميز خريطة تسلسل استدعاء الدوال البرمجية.
تحسينات على المزامنة
عدّل فريق ART مسارات رموز MonitorEnter/MonitorExit، وقلّل من اعتمادنا على حواجز الذاكرة التقليدية في ARMv8، واستبدلها بتعليمات أحدث (acquire/release) حيثما أمكن ذلك.
طُرق أصلية أسرع
تتوفّر استدعاءات أصلية أسرع لواجهة Java الأصلية (JNI) باستخدام التعليقَين التوضيحيَين @FastNative
و@CriticalNative
. تؤدي عمليات التحسين المضمّنة في وقت تشغيل ART إلى تسريع عمليات نقل البيانات عبر JNI واستبدال الرمز !bang JNI الذي تم إيقافه نهائيًا. لا تؤثّر التعليقات التوضيحية في الطرق غير الأصلية، وهي متاحة فقط لرمز لغة Java الأساسي على bootclasspath
(بدون تحديثات على "متجر Play").
تتيح التعليقات التوضيحية @FastNative
استخدام طرق غير ثابتة. استخدِم هذا النوع إذا كان أحد الإجراءات يصل إلى jobject
كمعلَمة أو قيمة معادة.
يوفّر التعليق التوضيحي @CriticalNative
طريقة أسرع لتنفيذ الطرق الأصلية، مع القيود التالية:
-
يجب أن تكون الطرق ثابتة، أي بدون كائنات للمَعلمات أو قيم الإرجاع أو
this
ضمني. - يتم تمرير الأنواع الأساسية فقط إلى الطريقة الأصلية.
-
لا تستخدم الطريقة الأصلية المَعلمتَين
JNIEnv
وjclass
في تعريف الدالة. -
يجب تسجيل الطريقة باستخدام
RegisterNatives
بدلاً من الاعتماد على الربط الديناميكي لواجهة JNI.
يمكن أن يؤدي استخدام @FastNative
إلى تحسين أداء الطريقة الأصلية بما يصل إلى 3 أضعاف، بينما يؤدي استخدام @CriticalNative
إلى تحسين الأداء بما يصل إلى 5 أضعاف. على سبيل المثال، عملية انتقال JNI تم قياسها على جهاز Nexus 6P:
استدعاء واجهة Java الأصلية (JNI) | وقت التنفيذ (بالنانو ثانية) |
---|---|
واجهة JNI العادية | 115 |
!bang JNI | 60 |
@FastNative |
35 |
@CriticalNative |
25 |