فقط في الوقت المناسب وأوضح تجميع

يعتبر التجميع في الوقت المناسب طريقة لتحسين أداء البرامج المفسرة. أثناء التنفيذ ، يمكن تحويل البرنامج إلى كود أصلي لتحسين أدائه. يُعرف أيضًا باسم التجميع الديناميكي.

للتجميع الديناميكي بعض المزايا مقارنة بالتجميع الثابت. عند تشغيل تطبيقات Java أو C # ، يمكن لبيئة وقت التشغيل إنشاء ملف تعريف للتطبيق أثناء تشغيله. هذا يسمح بإنشاء المزيد من التعليمات البرمجية المحسنة. إذا تغير سلوك التطبيق أثناء تشغيله ، يمكن لبيئة وقت التشغيل إعادة ترجمة التعليمات البرمجية.

تتضمن بعض العيوب تأخيرات في بدء التشغيل ونفقات التجميع أثناء وقت التشغيل. للحد من الحمل ، يقوم العديد من مترجمي JIT فقط بترجمة مسارات التعليمات البرمجية المستخدمة بشكل متكرر.

نظرة عامة

تقليديا ، هناك طريقتان لتحويل التعليمات البرمجية المصدر إلى نموذج يمكن تشغيله على النظام الأساسي. يحول التجميع الثابت الرمز إلى لغة لمنصة معينة. يقوم المترجم بتنفيذ الكود المصدري مباشرة.

يحاول تجميع JIT استخدام فوائد كليهما. أثناء تشغيل البرنامج المفسر ، يحدد مترجم JIT الكود الأكثر استخدامًا ويجمعه في رمز الجهاز. اعتمادًا على المترجم ، يمكن القيام بذلك على طريقة أو قسم أصغر من التعليمات البرمجية.

تم وصف التجميع الديناميكي لأول مرة في ورقة كتبها ج. مكارثي على LISP في عام 1960.

تجميع فقط في الوقت المناسب ، JIT ، أو الترجمة الديناميكية ، هو تجميع يتم إجراؤه أثناء تنفيذ البرنامج. بمعنى ، في وقت التشغيل ، على عكس ما قبل التنفيذ. ما يحدث هو الترجمة إلى الكود الآلي. ترجع مزايا JIT إلى حقيقة أنه نظرًا لأن التجميع يحدث في وقت التشغيل ، فإن مترجم JIT لديه حق الوصول إلى معلومات وقت التشغيل الديناميكية التي تمكنه من إجراء تحسينات أفضل (مثل الوظائف المضمنة).

ما هو مهم لفهمه حول تجميع JIT ، هو أنه سيقوم بتجميع الرمز الثانوي في تعليمات كود الآلة الخاصة بالجهاز قيد التشغيل. بمعنى ، أن رمز الجهاز الناتج تم تحسينه لبنية وحدة المعالجة المركزية للجهاز قيد التشغيل.

بعض أمثلة JIT Compilers هي JVM (Java Virtual Machine) في Java و CLR (Common Language Runtime) ، في C #.

التاريخ

في البداية ، كان المترجم مسؤولاً عن تحويل لغة عالية المستوى (تُعرَّف بمستوى أعلى من المُجمِّع) إلى كود كائن (تعليمات الآلة) ، والتي سيتم بعد ذلك ربطها (بواسطة رابط) في ملف تنفيذي.

في مرحلة ما من تطور اللغات ، يقوم المترجمون بترجمة لغة عالية المستوى إلى كود زائف ، والذي سيتم بعد ذلك تفسيره (بواسطة مترجم) لتشغيل برنامجك. أدى ذلك إلى التخلص من التعليمات البرمجية الهدف والملفات التنفيذية ، وسمح لهذه اللغات بأن تكون محمولة على أنظمة تشغيل وأنظمة أساسية متعددة. كان باسكال (الذي تم تجميعه إلى P-Code) واحدًا من أوائل ؛ تعد Java و C # من الأمثلة الأكثر حداثة. في النهاية ، تم استبدال مصطلح P-Code بـ bytecode ، نظرًا لأن معظم العمليات الزائفة تكون بطول بايت.

المترجم Just-In-Time (JIT) هو ميزة لمترجم وقت التشغيل ، والتي بدلاً من تفسير الرمز الثانوي في كل مرة يتم فيها استدعاء طريقة ما ، سيقوم بتجميع الرمز الثانوي في تعليمات رمز الجهاز الخاصة بالجهاز قيد التشغيل ، ثم استدعاء هذا بدلا من ذلك. من الناحية المثالية ، ستتغلب كفاءة تشغيل كود الكائن على عدم كفاءة إعادة تجميع البرنامج في كل مرة يتم تشغيلها.

سيناريو نموذجي

يتم تحويل الكود المصدري بالكامل إلى كود الآلة

سيناريو JIT

سيتم تحويل الكود المصدري إلى لغة تجميع مثل البنية [لـ ex IL (لغة وسيطة) لـ C # ، ByteCode لجافا].

يتم تحويل الكود الوسيط إلى لغة الآلة فقط عندما يحتاج التطبيق إلى تحويل الرموز المطلوبة فقط إلى رمز الجهاز.

مقارنة JIT مقابل Non-JIT

في JIT ، لا يتم تحويل كل الكود إلى رمز الجهاز أولاً ، سيتم تحويل جزء من الكود الضروري إلى رمز آلة ، ثم إذا لم تكن هناك طريقة أو وظيفة تسمى في الجهاز ، فسيتم تحويلها إلى رمز آلة ، مما يقلل العبء على وحدة المعالجة المركزية. نظرًا لأنه سيتم إنشاء رمز الجهاز في وقت التشغيل ، فإن مترجم JIT سينتج رمز الجهاز الذي تم تحسينه لتشغيل بنية وحدة المعالجة المركزية للجهاز.

بعض الأمثلة على JIT هي:

  • جافا: JVM (آلة جافا الافتراضية)
  • C #: CLR (وقت تشغيل اللغة العامة)
  • Android: DVM (Dalvik Virtual Machine) أو ART (Android RunTime) في الإصدارات الأحدث

ينفذ Java Virtual Machine (JVM) الرمز الثانوي ويحافظ على عدد مرات تنفيذ الوظيفة. إذا تجاوز هذا العدد حدًا محددًا مسبقًا ، يقوم JIT بتجميع الكود إلى لغة الآلة التي يمكن تنفيذها مباشرة بواسطة المعالج (على عكس الحالة العادية التي يقوم فيها javac بترجمة الشفرة إلى رمز ثانوي ثم Java ، يقوم المترجم الفوري بترجمة هذا الرمز الثانوي سطرًا سطرًا إلى سطر. كود الجهاز وينفذ).

أيضًا في المرة التالية التي يتم فيها حساب هذه الوظيفة ، يتم تنفيذ نفس الكود المترجم مرة أخرى على عكس التفسير العادي الذي يتم فيه تفسير الكود مرة أخرى سطرًا بسطر. هذا يجعل التنفيذ أسرع.