JIT (Just-In-Time) هي تقنية تجميع ديناميكي تحول البايت كود أو التمثيل الوسيط للبرنامج إلى تعليمات آلية مباشرة أثناء التنفيذ. في Android، ظهر مترجم JIT لأول مرة في الإصدار 2.2 Froyo كجزء من الآلة الافتراضية Dalvik وسرّع تنفيذ التطبيقات بمقدار 2–5 مرات. وفقًا لـ Google, 2024، يجمع JIT الحديث في ART بين التفسير والتجميع المحدد للطرق الساخنة.
الخلاصة
Just-In-Time (JIT) هي طريقة تجميع يتم فيها تحويل الكود المصدري أو البايت كود إلى تعليمات آلية ليس مسبقًا (كما في AOT)، ولكن في لحظة أول استدعاء للقسم المقابل من البرنامج. المصطلح “Just-In-Time” يعني أن التجميع يحدث “في الوقت المناسب” — مباشرة قبل التنفيذ.
مفهوم JIT موجود منذ الستينيات، لكنه انتشر على نطاق واسع مع ظهور الآلة الافتراضية لجافا في عام 1995. يسمح JIT بالجمع بين قابلية نقل البايت كود (اكتب مرة واحدة — شغّل في أي مكان) مع أداء قريب من الكود الأصلي. في Java HotSpot VM، يقوم مترجم JIT بتحليل الكود المنفذ ويجمع فقط الأقسام الأكثر أهمية، مما يوفر الوقت والذاكرة.
يستقبل مترجم JIT البايت كود كمدخل، ويفسره، ويجمع الإحصائيات بالتوازي. عندما يتم استدعاء قسم معين من الكود (طريقة، حلقة) بشكل متكرر، يقرر JIT تجميعه. يتم تخزين الكود الآلي المجمع في ذاكرة تخزين مؤقت — عند الاستدعاءات المتكررة، يُستخدم الإصدار المجمع بالفعل. هذا يوفر تسريعًا دون الحاجة إلى تجميع البرنامج بأكمله.
// مثال: تصبح الطريقة ساخنة بعد استدعاءات متعددة
public class HotMethod {
private int compute(int n) {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += i * i;
}
return sum;
}
}
// استدعاء 500 مرة في حلقة — سيجمع JIT compute
for (int t = 0; t < 500; t++) {
hot.compute(1000);
}
في Android، مر التجميع JIT بثلاث مراحل من التطور. المرحلة الأولى — Dalvik بدون JIT (Android 1.0–2.1): تفسير خالص للبايت كود DEX. المرحلة الثانية — Dalvik مع JIT (Android 2.2–4.4): إدخال مترجم JIT، الذي سرّع التطبيقات بمقدار 2–5 مرات. المرحلة الثالثة — ART مع JIT هجين (Android 7.0+): عودة JIT بشكل جديد.
تم تنفيذ JIT في Dalvik كمترجم قائم على التتبع. لم يحلل الطرق الفردية، بل سلاسل التعليمات (التتبعات) التي يتم تنفيذها بشكل متسلسل بشكل متكرر. هذا سمح بتجميع مسارات تنفيذ كاملة، بما في ذلك طرق متعددة. كان هذا النهج فعالاً لـ معالجات الأجهزة المحمولة ذات ذاكرات التعليمات المؤقتة الصغيرة، حيث كان التتبع المجمع يتسع في ذاكرة L1 المؤقتة.
ابتداءً من Android 7.0 Nougat، يستخدم ART JIT القائم على الطرق — يجمع الطرق الفردية بناءً على ملفات تعريف التنفيذ. يعمل JIT هذا بشكل أسرع بكثير من Dalvik JIT: وقت التجميع النموذجي لطريقة واحدة هو 0.5–1 مللي ثانية مقارنة بـ 3–5 مللي ثانية في Dalvik. يتم تخزين الكود المجمع في منطقة ذاكرة منفصلة (ذاكرة تخزين مؤقت لكود JIT) بدلاً من كومة التطبيق، مما يقلل التجزئة.
| المعامل | Dalvik JIT | ART JIT |
|---|---|---|
| النوع | قائم على التتبع | قائم على الطرق |
| سرعة التجميع | 3–5 مللي ثانية/طريقة | 0.5–1 مللي ثانية/طريقة |
| حد التجميع | ~200 استدعاء | ديناميكي |
| ذاكرة الكود المؤقتة | في كومة التطبيق | ذاكرة كود JIT المؤقتة |
| التوصيف | داخلي | ملفات .prof خارجية |
الآلية المركزية لـ JIT هي كشف الطرق الساخنة. كل استدعاء لطريقة يزيد عدادًا داخليًا. عندما يعبر العداد الحد، تُوسم الطريقة كـ “ساخنة” وتُرسل للتجميع. في Dalvik، كان الحد ثابتًا (~200 استدعاء). في ART، يتم ضبط العدادات ديناميكيًا اعتمادًا على الموارد المتاحة للجهاز.
تتضمن عملية التجميع عدة مراحل. الأولى — تحليل البايت كود: يفحص JIT تدفق التعليمات ويبني رسمًا بيانيًا لتدفق البيانات. الثانية — التحسين: تضمين الطرق الصغيرة، إزالة الكود الميت، طي الثوابت. الثالثة — توليد الكود: تحويل الرسم البياني المحسّن إلى تعليمات آلية لمعمارية CPU محددة (ARM, ARM64, x86).
// توضيح التضمين — سيضمّن JIT نص الطريقة
public int inlineExample() {
return square(5);
}
private int square(int x) {
return x * x;
} // سيستبدل JIT الاستدعاء بـ return 5 * 5;
تقنية خاصة لـ JIT — الاستبدال على المكدس (OSR). إذا كانت الطريقة تحتوي على حلقة طويلة لا تنتهي لمئات التكرارات، يمكن لـ JIT تجميع الحلقة “على الطاير” واستبدال النسخة المفسرة بالنسخة المجمعة مباشرة أثناء التنفيذ. OSR فعال بشكل خاص للمهام الحسابية: التصيير، معالجة الصور، التشفير.
JIT و AOT هما نهجان للتجميع بمقايضات متعاكسة. يضحي JIT بسرعة التشغيل الأولى مقابل حجم توزيع مضغوط وقابلية للتكيف. يضحي AOT بوقت التثبيت ومساحة القرص مقابل أقصى أداء من الثانية الأولى. لا يوجد نهج أفضل بشكل مطلق — الاختيار يعتمد على السيناريو.
الميزة الرئيسية لـ JIT هي التحسين التكيفي. يمكن لـ JIT استخدام معلومات التوصيف غير المتاحة لـ AOT: أنواع الكائنات الدقيقة، تردد الاستدعاء الفعلي، أنماط التفرع الحقيقية. هذا يسمح بتطبيق تحسينات عدوانية مستحيلة مع التجميع الثابت. على سبيل المثال، يمكن لـ JIT إلغاء افتراضية استدعاءات الطرق إذا تم العثور على نوع مستقبل واحد فقط عمليًا.
| المعيار | JIT | AOT |
|---|---|---|
| وقت التثبيت | فوري | يعتمد على الحجم |
| التشغيل الأول | أبطأ (تسخين) | سريع |
| مساحة القرص | أدنى حد | +15–30% |
| قابلية التكيف | عالية | منخفضة |
| استهلاك CPU | قمم أثناء التجميع | مستقر |
التجميع JIT مفضل عندما يكون النشر السريع وتوفير مساحة القرص مهمين. في سياق تطوير الأجهزة المحمولة، JIT مثالي للتطبيقات التي يتم تحديثها بشكل متكرر (اختبار A/B، التصحيحات السريعة). JIT مناسب أيضًا أثناء التطوير، عندما يُعاد بناء الكود عشرات المرات في اليوم — كل ثانية يتم توفيرها في التجميع تسرّع دورة التغذية الراجعة.
JIT يوفر للمطورين عددًا من المزايا العملية. الأولى — حجم صغير لملف APK. مع نهج JIT، يتم تعبئة البايت كود فقط (DEX) في APK، الذي يشغل مساحة أقل بنسبة 20–30% من الكود الأصلي المجمع. للمستخدمين ذوي مساحة التخزين الداخلية المحدودة، هذه ميزة كبيرة.
الميزة الثانية هي التكيف مع الجهاز. يجمع JIT الكود مع مراعاة المعمارية الفعلية للCPU، حجم RAM، والتحميل الحالي. على سبيل المثال، على جهاز بسعة 2 جيجابايت RAM، قد يجمع JIT بشكل أقل عدوانية لتوفير الذاكرة، بينما على جهاز رائد بسعة 12 جيجابايت، يمكنه تطبيق جميع التحسينات الممكنة. التجميع AOT، من ناحية أخرى، يثبت القرار في وقت التثبيت.
يظل البايت كود مستقلاً عن المنصة، مما يبسط توزيع التطبيقات. يعمل ملف APK واحد على أجهزة ARM و ARM64 و x86، ويقوم JIT بتوليد كود أصلي لكل معمارية. نهج AOT يتطلب إما تضمين متغيرات متعددة من الكود الأصلي في APK (زيادة الحجم) أو تجميع نسخة منفصلة لكل معمارية.
العيب الرئيسي لـ JIT هو تأخير التسخين. يواجه المستخدم بطئًا في الثواني الأولى من عمل التطبيق بينما يقوم JIT بتجميع الطرق الساخنة. في الألعاب، يظهر هذا كتقطيع في المستويات الأولية. في التطبيقات ذات الرسوم المتحركة — انتقالات متقطعة بين الشاشات.
العيب الثاني — استهلاك الطاقة. عملية التجميع تثقل CPU بشكل كبير، مما يزيد استهلاك الطاقة بنسبة 10–20% خلال فترة التسخين. على الأجهزة التي تعمل بالبطارية، هذا يقلل من عمر البطارية. ملحوظ بشكل خاص في سيناريوهات إعادة التشغيل المتكررة للتطبيقات (تعدد المهام بذاكرة محدودة، حيث يقوم النظام بتفريغ وإعادة تحميل العمليات).
مشكلة أخرى — تجزئة ذاكرة JIT المؤقتة. يتم تخزين الكود المجمع في منطقة ذاكرة مستمرة. عند تحميل فئات جديدة وتجميع طرق إضافية، تتجزأ الذاكرة المؤقتة، مما يزيد من الأعباء الإدارية للذاكرة. في Dalvik، تم حل هذه المشكلة بالتنظيف الدوري للذاكرة المؤقتة؛ في ART، يتم تخصيص ذاكرة JIT المؤقتة بشكل منفصل عن الكومة وتستخدم استراتيجية إزالة تجزئة خاصة بها.
النهج الحديث في ART — التجميع الهجين، الذي يجمع نقاط القوة في JIT و AOT. أثناء تثبيت التطبيق، لا يتم تنفيذ أي تجميع — فقط التحقق من البايت كود (verify). هذا يضمن تثبيتًا سريعًا واستخدامًا أدنى للمساحة. يتم تشغيل الإطلاقات الأولى في وضع التفسير مع تجميع JIT للطرق الساخنة — يحصل المستخدم على أداء مقبول دون أوقات انتظار طويلة.
بالتوازي، يعمل محدد ملفات تعريف في الخلفية يجمع بيانات حول الاستخدام الفعلي. بعد 2–3 إطلاقات كاملة للتطبيق، يصل ملف التعريف إلى درجة كافية من الاكتمال، ويقوم النظام بتشغيل dex2oat لتجميع الطرق الساخنة إلى كود أصلي. يتم تنفيذ هذه العملية في الخلفية عندما لا يكون الجهاز محملاً (شحن، شاشة مطفأة). بعد اكتمال AOT في الخلفية، يحقق التطبيق أداءً مماثلاً للتجميع AOT الكامل.
# بدء إجباري للتجميع في الخلفية
adb shell cmd package compile -m speed-profile -f com.example.app
# عرض حالة التجميع
adb shell cmd package dump-profiles com.example.app
وفقًا لـ Google I/O 2017، قلل التجميع الهجين وقت تثبيت التطبيقات بنسبة 30–50% مقارنة بـ AOT الخالص. انخفضت مساحة القرص المشغولة على قسم النظام بنسبة 20–30%. في الوقت نفسه، يتطابق الأداء بعد التجميع في الخلفية مع مستوى AOT الكامل. السيناريو الوحيد حيث يقل الهجين عن AOT هو التشغيل الأول مباشرة بعد التثبيت: يعمل التطبيق في وضع JIT وقد يكون أبطأ بنسبة 10–15%.
الأسئلة الشائعة
JIT هو طريقة لتسريع البرنامج حيث يتم ترجمة الكود إلى لغة آلية ليس مسبقًا، بل في أجزاء أثناء التشغيل. الأقسام الأكثر تكرارًا تُجمع وتُخزَّن مؤقتًا، بينما تبقى النادرة في شكلها الأصلي.
JIT يجمع الكود أثناء التنفيذ، مما يوفر المساحة ويسرّع التثبيت. AOT يجمع كل الكود مسبقًا — يبدأ التطبيق بشكل أسرع لكنه يتطلب مساحة قرص ووقت تثبيت أكبر.
JIT لم يُزل — بل تطور. في Android 5.0، تم استبدال Dalvik مع JIT بـ ART مع AOT خالص. في Android 7.0، عاد JIT إلى ART كجزء من نظام هجين حيث يعمل جنبًا إلى جنب مع تجميع AOT في الخلفية للحصول على أداء أمثل.
JIT يزيد استهلاك الطاقة بنسبة 10–20% خلال فترة التسخين بسبب حمل CPU. بعد اكتمال تجميع الطرق الساخنة، يعود استهلاك الطاقة إلى مستوياته الطبيعية. وضع ART الهجين يقلل هذه القمم من خلال التجميع في الخلفية.
نعم، في سيناريوهات الحسابات المكثفة. قد يلاحظ المستخدم بطئًا في الثواني الأولى من تشغيل التطبيق أو في بداية اللعبة. في الإصدارات الحديثة من Android (8.0+)، يقلل الوضع الهجين هذا التأثير بفضل التجميع المحدد.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا