JVM Internals، Part 1 - Class Loader

تم إعداد ترجمة للمقال خصيصًا لطلاب دورة Java Developer .




في هذه السلسلة من المقالات ، سأتحدث عن كيفية عمل Java Virtual Machine. اليوم ننظر إلى آلية تحميل الفئات في JVM .

تقع Java Virtual Machine في قلب النظام البيئي لتقنية Java. يجعل من الممكن لبرامج Java تنفيذ مبدأ "الكتابة بمجرد تشغيله في كل مكان". مثل الأجهزة الافتراضية الأخرى ، فإن JVM هو جهاز كمبيوتر تجريدي. تتمثل المهمة الرئيسية لـ JVM في تحميل ملفات فئة وتنفيذ الرمز الفرعي الوارد فيها.

يتضمن JVM مكونات متنوعة ، مثل لودر Class ، و Garbage Collector (إدارة الذاكرة التلقائية) ، ومترجم ، ومترجم JIT ، ومكونات التحكم في التدفق. في هذه المقالة ، سوف ننظر إلى محمل الصف.

يقوم برنامج تحميل الفئة بتحميل ملفات الفئة لكل من تطبيقك وواجهة برمجة تطبيقات Java. يتم فقط تحميل ملفات فئة Java API المطلوبة بالفعل عند تشغيل البرنامج في الجهاز الظاهري.

يتم تنفيذ رمز البايت بواسطة مشغل التنفيذ.



ما هو تحميل الصف؟


تحميل الفئة هو البحث عن الأنواع (الفئات والواجهات) وتحميلها بشكل حيوي أثناء تنفيذ البرنامج. نوع البيانات في ملفات فئة ثنائية.

خطوات تحميل الفئة


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

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

ملاحظة - يكون مُحمل الفصل ، بالإضافة إلى تحميل الفئات ، مسؤولًا أيضًا عن العثور على الموارد. المورد هو بعض البيانات (على سبيل المثال ، ملف ".class" وبيانات التكوين والصور) التي تم تحديدها باستخدام مسار مجردة مفصولة بحرف "/". عادة ما يتم حزم الموارد مع تطبيق أو مكتبة بحيث يمكن استخدامها في رمز التطبيق أو المكتبة.

آلية تحميل الفئة في Java


ملاحظة المترجم - يصف هذا القسم سلوك java <9 ، في java 9+ كانت هناك تغييرات صغيرة ، موضحة أدناه.

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

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

  • مخبأ
  • الوالد
  • بووتلوأدر نفسه

يتحقق مُحمل الفصل أولاً لمعرفة ما إذا كان قد تم تحميله من قبل. إذا كان الأمر كذلك ، فسيتم إرجاع نفس الفئة التي تم إرجاعها في المرة الأخيرة (الفئة المخزنة في ذاكرة التخزين المؤقت). إذا لم يكن الأمر كذلك ، يتم إعطاء الوالد الفرصة لتحميل الفصل. يتم تكرار هاتين الخطوتين بشكل متكرر في العمق. في حالة إرجاع الأصل خالٍ (أو طرح ClassNotFoundException ) ، يبحث المُحمل عن الفصل بمفرده.

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

قام Java SE Platform API بالتعريف التاريخي لمجموعتي التحميل:

مُحمل فئة Bootstrap (مُحمل أساسي ، محمل أساسي) - يُحمّل فصولًا من bootstrap classpath.

مُحمّل فئة النظام (المُحمِّل الأصل ) - هو الفئة الأصل لمُحمّلات الفئة الجديدة ، وكقاعدة عامة ، مُحمِّل الفئة المُستخدم في تحميل التطبيق وتشغيله.

JDK 9+ لوادر فئة


محمل فئة التطبيق - يشيع استخدامه لتحميل فئات التطبيقات من classpath. وهو أيضًا أداة تحميل التشغيل الافتراضية لبعض وحدات JDK التي تحتوي على أدوات مساعدة أو تقوم بتصدير واجهة برمجة تطبيقات الأدوات المساعدة. ( ملاحظة المترجم: على سبيل المثال ، jdk.jconsole ، jdk.jshell ، إلخ. )

أداة تحميل فئة النظام الأساسي - الأحمال المحددة (بناءً على الأمان / الأذونات) وحدات Java SE و JDK. على سبيل المثال ، java.sql.

أداة تحميل الفئة Bootstrap - لتحميل وحدات Java SE و JDK الأساسية.

تعمل اللوادر المدمجة الثلاثة هذه معًا على النحو التالي:

  • يبحث مُحمل فئة التطبيق أولاً عن الوحدات النمطية المسماة المعرفة لجميع اللوادر المدمجة. إذا تم تعريف وحدة مناسبة لإحدى هذه اللوادر ، فإن اللودر يقوم بتحميل الفئة. إذا لم يتم العثور على الفئة في الوحدة النمطية المسماة المحددة لأحد هذه اللوادر ، فسيقوم مُحمِّل فئة التطبيق بتفويضها إلى الأصل. إذا لم يتم العثور على الفئة من قبل الأصل ، فإن أداة تحميل فئة التطبيق تبحث عنها في classpath. يتم تحميل الفئات الموجودة في classpath كأعضاء في الوحدة النمطية غير المسماة لهذا المحمل.
  • يبحث مُحمل فئة النظام الأساسي عن الوحدات النمطية المحددة المعرفة لجميع اللوادر المدمجة. إذا تم تعريف وحدة مناسبة لإحدى هذه اللوادر ، فإن اللودر يقوم بتحميل الفئة. إذا لم يتم العثور على الفئة في الوحدة النمطية المسماة المحددة لأحد هذه اللوادر ، فإن محمل الفئة الأساسي يقوم بتفويضها إلى الأصل.
  • يبحث مُحمل فئة bootstrap عن الوحدات النمطية المسماة المعرفة لنفسه. إذا لم يتم العثور على الفئة في الوحدة النمطية المسماة المعرّفة لمحمل الإقلاع bootstrap ، يبحث محمل الإقلاع bootstrap عن الملفات والدلائل التي تمت إضافتها إلى classpath bootstrap باستخدام -Xbootclasspath / a معلمة (يسمح لك بإضافة الملفات والدلائل إلى classpath bootstrap). يتم تحميل الفئات الموجودة في classstath bootstrap كأعضاء في الوحدة النمطية غير المسماة لهذا المحمل.

لعرض برامج تحميل الفئة المضمنة ، يمكنك استخدام التعليمات البرمجية التالية:

 package ru.deft.homework; import java.sql.Date; public class BuiltInClassLoadersDemo { public static void main(String[] args) { BuiltInClassLoadersDemo demoObject = new BuiltInClassLoadersDemo(); ClassLoader applicationClassLoader = demoObject.getClass().getClassLoader(); printClassLoaderDetails(applicationClassLoader); // java.sql classes are loaded by platform classloader java.sql.Date now = new Date(System.currentTimeMillis()); ClassLoader platformClassLoder = now.getClass().getClassLoader(); printClassLoaderDetails(platformClassLoder); // java.lang classes are loaded by bootstrap classloader ClassLoader bootstrapClassLoder = args.getClass().getClassLoader(); printClassLoaderDetails(bootstrapClassLoder); } private static void printClassLoaderDetails(ClassLoader classLoader) { // bootstrap classloader is represented by null in JVM if (classLoader != null) { System.out.println("ClassLoader name : " + classLoader.getName()); System.out.println("ClassLoader class : " + classLoader.getClass().getName()); } else { System.out.println("Bootstrap classloader"); } } } 

عن طريق تشغيل هذا الرمز على Amazon Corretto 11.0.3 مثبتًا علىي ، نحصل على النتيجة التالية:

 ClassLoader name : app ClassLoader class : jdk.internal.loader.ClassLoaders$AppClassLoader ClassLoader name : platform ClassLoader class : jdk.internal.loader.ClassLoaders$PlatformClassLoader Bootstrap classloader 

يمكنك معرفة المزيد حول واجهة برمجة تطبيقات ClassLoader هنا (JDK 11) .

Source: https://habr.com/ru/post/ar468193/


All Articles