ليس سراً أن جافا في الوقت الحالي هي واحدة من لغات البرمجة الأكثر شعبية في العالم. تاريخ الإصدار الرسمي لـ Java هو 23 مايو 1995.
تم تخصيص هذه المقالة للأساسيات: فهي تحدد الميزات الأساسية للغة ، والتي ستكون مفيدة للمبتدئين "javists" ، وسيتمكن مطورو Java من ذوي الخبرة من تحديث معارفهم.
* تم إعداد المقال على أساس تقرير أعده يوجين فريمان - مطور جافا لـ IntexSoft.
المقالة تحتوي على روابط لمواد خارجية .

1. JDK ، JRE ، JVM
Java Development Kit هي مجموعة تطوير تطبيقات
Java . يتضمن
أدوات تطوير Java و Java Runtime Environment (
JRE ).
تتضمن
أدوات تطوير Java حوالي 40 أداة مختلفة: javac (برنامج التحويل البرمجي) ، java (مشغل التطبيقات) ، javap (أداة فك تجميع ملفات java class) ، jdb (java debugger) ، إلخ.
وقت تشغيل JRE عبارة عن حزمة من كل ما هو مطلوب لتشغيل برنامج Java مترجم. يتضمن الجهاز الظاهري
JVM ومكتبة Java Class .
JVM هو برنامج مصمم لتنفيذ bytecode. الميزة الأولى لـ JVM هي مبدأ
"الكتابة مرة واحدة ، ركض في أي مكان" . هذا يعني أن التطبيق المكتوب بلغة جافا سيعمل على جميع الأنظمة الأساسية. هذه ميزة كبيرة لـ JVM و Java نفسها.
قبل Java ، تم كتابة العديد من برامج الكمبيوتر لأنظمة كمبيوتر محددة ، وتم إعطاء التفضيل لإدارة الذاكرة اليدوية ، حيث أنها أكثر كفاءة ويمكن التنبؤ بها. منذ النصف الثاني من التسعينيات ، بعد ظهور Java ، أصبحت الإدارة التلقائية للذاكرة ممارسة شائعة.
هناك العديد من تطبيقات JVM ، التجارية والمفتوحة المصدر. أحد أهداف إنشاء JVMs الجديدة هو زيادة الأداء لمنصة معينة. تتم كتابة كل JVM بشكل منفصل للمنصة ، في حين أنه من الممكن كتابتها بحيث تعمل بشكل أسرع على منصة محددة. تطبيق JVM الأكثر شيوعًا هو نقطة اتصال
OpenJDK JVM. هناك أيضا تطبيقات
IBM J9 ،
Excelsior JET .
2. تنفيذ كود JVM
وفقًا
لمواصفات Java SE ، من أجل تشغيل التعليمات البرمجية في JVM ، تحتاج إلى إكمال 3 خطوات:
- قم بتنزيل bytecode و إنشاء مثيل لـ Class
تحدث تقريبًا ، من أجل الحصول على JVM ، يجب تحميل الفصل. هناك فئات محمل منفصلة لهذا ، سنعود لهم في وقت لاحق قليلا. - ربط أو ربط
بعد تحميل الفصل الدراسي ، تبدأ عملية الربط ، التي يتم فيها تحليل الرمز الفرعي والتحقق منه. عملية الربط ، بدورها ، تتم في 3 خطوات:
- التحقق من صحة أو التحقق من الرمز البريدي: صحة التعليمات ، وإمكانية تجاوز سعة مكدس الذاكرة المؤقتة في هذا القسم من الكود ، يتم التحقق من توافق أنواع المتغيرات ؛ تحقق يحدث مرة واحدة لكل فئة.
- التحضير أو التحضير: في هذه المرحلة ، وفقًا للمواصفات ، يتم تخصيص الذاكرة للحقول الثابتة ويحدث التهيئة ؛
- الدقة أو الدقة: دقة الروابط الرمزية (عندما نفتح في bytecode الملفات ذات الامتداد .class ، نرى القيم العددية بدلاً من الروابط الرمزية). - تهيئة كائن Class الناتج
في المرحلة الأخيرة ، تتم تهيئة الفصل الذي أنشأناه ، ويمكن لـ JVM البدء في تنفيذه.
3. رافعات الطبقة وتسلسلها الهرمي
العودة إلى لوادر الفصول الدراسية ، هذه فصول خاصة تشكل جزءًا من JVM. انهم تحميل الطبقات في الذاكرة وإتاحتها للتنفيذ. تعمل اللوادر مع جميع الفئات: كلانا وتلك اللازمة مباشرة لجافا.
تخيل الموقف: لقد كتبنا طلبنا ، بالإضافة إلى الفصول القياسية ، هناك فصولنا ، وهناك الكثير منها. كيف ستعمل JVM مع هذا؟ تنفذ Java التحميل المؤجل للفئة ، بمعنى آخر التحميل البطيء. هذا يعني أن تحميل الفئات لن يتم حتى يتم استدعاء التطبيق إلى الفصل.
الطبقة محمل التسلسل الهرمي

محمل الفئة الأولى هو محمل الفصل
Bootstrap . هو مكتوب في C ++. هذا هو المُحمل الأساسي الذي يقوم بتحميل جميع فئات النظام من أرشيف
rt.jar . في الوقت نفسه ، هناك اختلاف بسيط بين فئات التحميل من
rt.jar وفئاتنا : عندما تقوم JVM بتحميل الفئات من
rt.jar ، فإنها لا تنفذ جميع خطوات التحقق التي يتم تنفيذها عند تحميل أي ملف فئة آخر منذ تدرك JVM في البداية أن جميع هذه الفئات تم التحقق من صحتها بالفعل. لذلك ، يجب ألا تدرج أيًا من ملفاتك في هذا الأرشيف.
محمل الإقلاع التالي هو محمل
الإضافات classloader. يقوم بتحميل فئات التمديد من المجلد
jre / lib / ext . افترض أنك تريد تحميل فصل في كل مرة يتم فيها تشغيل جهاز Java. للقيام بذلك ، يمكنك نسخ ملف الفئة المصدر إلى هذا المجلد ، وسيتم تحميله تلقائيًا.
محمل الإقلاع الآخر هو أداة تحميل
النظام . يتم تحميل الفئات من classpath التي حددناها عند بدء تشغيل التطبيق.
تحدث عملية تحميل الفئات في التسلسل الهرمي:
- أولاً وقبل كل شيء ، نطلب البحث في ذاكرة التخزين المؤقت System Class Loader (تحتوي ذاكرة التخزين المؤقت لمحمّل النظام على فئات تم تحميلها بالفعل بها) ؛
- إذا لم يتم العثور على الفئة في ذاكرة التخزين المؤقت لمحمل النظام ، فنحن ننظر إلى أداة تحميل الفئة cache Extension ؛
- إذا لم يتم العثور على الفئة في ذاكرة التخزين المؤقت لمحمل الإضافات ، يتم طلب الفصل من محمل الإقلاع.
إذا لم يتم العثور على الفئة في ذاكرة التخزين المؤقت Bootstrap ، فإنه يحاول تحميل هذه الفئة. إذا تعذر على Bootstrap تحميل الفئة ، فإنه يفوض تحميل الفئة إلى أداة تحميل الملحق. إذا تم تحميل الفئة في هذه المرحلة ، فستظل في ذاكرة التخزين المؤقت الخاصة بملحق class class ، ويكتمل تحميل الفئة.
4. هيكل ملف الطبقة وعملية التمهيد
ننتقل مباشرة إلى هيكل ملفات الفصل.
يتم تصنيف فئة واحدة مكتوبة بلغة جافا في ملف واحد بالملحق .class. إذا كان هناك عدة فئات في ملف Java الخاص بنا ، فيمكن تجميع ملف Java واحد في عدة ملفات مع ملحق .class - bytecode files من هذه الفئات.
يتم تخزين جميع الأرقام والسلاسل والمؤشرات إلى الفئات والحقول والأساليب في مجمع
ثابت - منطقة ذاكرة
مساحة Meta . يتم تخزين وصف الفصل في نفس المكان ويحتوي على الاسم والمعدلات والفئات الفائقة والواجهات الفائقة والحقول والأساليب والسمات. السمات ، بدورها ، قد تحتوي على أي معلومات إضافية.
وبالتالي ، عند تحميل الطبقات:
- قراءة ملف الفصل ، أي التحقق من صحة التنسيق
- يتم إنشاء تمثيل فئة في تجمع ثابت (مساحة التعريف)
- يتم تحميل الطبقات الفائقة والواجهات الفائقة ؛ إذا لم يتم تحميلها ، فلن يتم تحميل الفصل نفسه
5. تنفيذ Bytecode على JVM
بادئ ذي بدء ، لتنفيذ الرمز الفرعي ، يمكن لـ JVM
تفسيره . التفسير عملية بطيئة إلى حد ما. في عملية التفسير ، يقوم المترجم "بتشغيل" سطراً سطراً من خلال ملف الفصل وترجمته إلى أوامر مفهومة من قبل JVM.
أيضًا ، يمكن لـ JVM
بثها ، أي ترجمة إلى رمز الجهاز الذي سيتم تنفيذه مباشرة على وحدة المعالجة المركزية.
لن يتم تفسير الأوامر التي يتم تنفيذها بشكل متكرر ، ولكن سيتم بثها على الفور.
6. تجميع
المحول البرمجي هو برنامج يقوم بتحويل أجزاء مصدر البرامج المكتوبة بلغة برمجة عالية المستوى إلى برنامج لغة الآلة "المفهوم" لجهاز الكمبيوتر.
يتم تقسيم المجمعين إلى:
- لا الأمثل
- تحسين بسيط (عميل Hotspot): العمل بسرعة ، ولكن قم بإنشاء رمز غير مثالي
- التحسين المعقد (Hotspot Server): قم بإجراء التحويلات المعقدة للتحسين قبل إنشاء الرمز البريدي
يمكن تصنيف المجمعين حسب وقت التجميع:
- المجمعين الديناميكي
انهم يعملون في وقت واحد مع البرنامج ، مما يؤثر على الأداء. من المهم أن تعمل هذه المترجمات على التعليمات البرمجية التي يتم تنفيذها في كثير من الأحيان. أثناء تنفيذ البرنامج ، يعرف JVM الشفرة التي يتم تنفيذها في أغلب الأحيان ، ومن أجل عدم تفسيرها باستمرار ، يقوم الجهاز الظاهري بترجمتها فورًا إلى أوامر سيتم تنفيذها بالفعل مباشرة على المعالج. - المجمعين ثابت
ترجمة أطول ، ولكن إنشاء رمز الأمثل للتنفيذ. من الايجابيات: لا يحتاجون إلى موارد أثناء تنفيذ البرنامج ، يتم تجميع كل طريقة باستخدام التحسينات.
7. تنظيم الذاكرة في جاوة
الكومة هي منطقة ذاكرة في Java تعمل وفقًا لنظام LIFO - "
Last in - Fisrt Out " أو "
Last In، First Out ".

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

لماذا التخلي عن جيل دائم؟ بادئ ذي بدء ، يرجع ذلك إلى حدوث خطأ مقترن بتدفق المنطقة: نظرًا لأن حجم بيرم كان ثابتًا ولم يتمكن من التوسع بشكل حيوي ، نفدت الذاكرة عاجلاً أم آجلاً ، وتم إلقاء خطأ ، وتعطل التطبيق.
تحتوي مساحة Meta على حجم ديناميكي ، ويمكن أن تتوسع في وقت التشغيل إلى أحجام ذاكرة JVM.
ميزات كومة الرئيسية:
- عندما تكون منطقة الذاكرة ممتلئة ، يلقي Java java.lang.OutOfMemoryError
- الوصول إلى كومة الذاكرة المؤقتة أبطأ من الوصول إلى المكدس
- يعمل جامع البيانات المهملة على جمع الكائنات غير المستخدمة
- كومة الذاكرة المؤقتة ، على عكس مكدس ، غير آمن لمؤشر الترابط ، حيث يمكن لأي مؤشر ترابط الوصول إليه
بناءً على المعلومات الواردة أعلاه ، ضع في اعتبارك كيفية إجراء إدارة الذاكرة باستخدام مثال بسيط:
public class App { public static void main(String[] args) { int id = 23; String pName = "Jon"; Person p = null; p = new Person(id, pName); } } class Person { int pid; String name; // constructors, getters/setters }
لدينا فئة تطبيقات تتكون فيها الطريقة
الرئيسية الوحيدة من:
- متغير
المعرف البدائي من النوع
int مع القيمة
23- متغير مرجع
pName من النوع
String مع القيمة
Jon- المتغير المرجعي
p of type
person
كما سبق ذكره ، عندما يتم استدعاء طريقة ، يتم إنشاء منطقة ذاكرة في الجزء العلوي من المكدس حيث يتم تخزين البيانات اللازمة لهذه الطريقة ليتم تخزينها.
في حالتنا ، هذا هو إشارة إلى فئة
الشخص : يتم تخزين الكائن نفسه على كومة الذاكرة المؤقتة ، ويتم تخزين الرابط على المكدس. يتم أيضًا الضغط على رابط السلسلة إلى المكدس ، ويتم تخزين السلسلة نفسها على الكومة في تجمع السلسلة. يتم تخزين البدائية مباشرة على المكدس.
لاستدعاء المُنشئ ذي المعلمات
Person (String) من الطريقة
main () في المكدس ، أعلى المكالمة
الرئيسية () السابقة ، يتم إنشاء إطار منفصل على المكدس الذي يخزن:
-
هذا - رابط للكائن الحالي
- قيمة
الهوية البدائية
- المتغير المرجعي
personName ، والذي يشير إلى سلسلة في String Pool.
بعد أن أطلقنا على المُنشئ ، يتم استدعاء
setPersonName () ، وبعد ذلك يتم إنشاء إطار جديد على المكدس مرة أخرى ، حيث يتم تخزين نفس البيانات: مرجع الكائن ، مرجع السطر ، القيمة المتغيرة.
وبالتالي ، عندما يتم تنفيذ طريقة
setter ، يختفي الإطار ، يتم مسح المكدس. بعد ذلك ، يتم تنفيذ المنشئ ، ويتم مسح الإطار الذي تم إنشاؤه للإنشاء ، وبعد ذلك تنتهي الطريقة
الرئيسية () من عملها ويتم إزالتها أيضًا من المكدس.
إذا تم استدعاء أساليب أخرى ، فسيتم أيضًا إنشاء إطارات جديدة لها في سياق هذه الأساليب المحددة.
8. جامع القمامة
يعمل
مجمّع البيانات المهملة على الكومة - برنامج يعمل على جهاز Java الظاهري الذي يتخلص من الكائنات التي لا يمكن الوصول إليها.
قد يكون JVMs المختلفة خوارزميات مختلفة لجمع القمامة ، وهناك أيضا جامعي القمامة مختلفة.
سنتحدث عن أبسط جامع
المسلسل GC . نحن نطلب جمع القمامة باستخدام
System.gc () .

كما ذكر أعلاه ، يتم تقسيم الكومة إلى منطقتين: الجيل الجديد والجيل القديم.
الجيل الجديد (جيل الشباب) يشمل 3 مناطق:
عدن ، و
Survivor 0 و
Survivor 1 .
الجيل القديم يشمل منطقة
الحيازة .
ماذا يحدث عندما ننشئ كائنًا في Java؟
بادئ ذي بدء ، الكائن يقع في
عدن . إذا قمنا بالفعل بإنشاء العديد من الكائنات ولم يكن هناك مساحة إضافية في
Eden ، فإن أداة تجميع مجمعي البيانات المهملة تعمل على تحرير الذاكرة وتحريرها. هذا هو ما يسمى
مجموعة القمامة الصغيرة - في الممر الأول ، ينظف منطقة
عدن ويضع الكائنات "الباقية" في منطقة
الناجين 0 . وبالتالي ، فإن منطقة
عدن محررة بالكامل.
إذا حدث أن منطقة
Eden ممتلئة مرة أخرى ، يبدأ جامع البيانات المهملة في العمل مع منطقة
Eden و
Survivor 0 ، والتي تشغلها حاليًا. بعد التطهير ، ستقع الأجسام الباقية على قيد الحياة في منطقة أخرى -
الناجين 1 ، بينما سيبقى الآخران نظيفين. عند تجميع البيانات المهملة اللاحقة ، سيتم تحديد
Survivor 0 مرة أخرى كمنطقة الوجهة. لهذا السبب من المهم أن تكون إحدى مناطق
الناجين فارغة دائمًا.
تراقب JVM الكائنات التي يتم نسخها باستمرار ونقلها من منطقة إلى أخرى. ولتحسين هذه الآلية ، بعد عتبة معينة ، يقوم جامع البيانات المهملة بنقل هذه الكائنات إلى المنطقة
الثابتة .
عندما لا تكون هناك مساحة كافية لكائنات جديدة في
Tenured ، فهناك مجموعة كاملة من البيانات المهملة -
Mark-Sweep-Compact .

خلال هذه الآلية ، يتم تحديد الكائنات التي لم تعد تُستخدم ، ويتم مسح المنطقة من هذه الكائنات ،
ويتم إلغاء تجزئة
منطقة الذاكرة
المنتقلة ، أي مليئة بالتسلسل مع الأشياء الضرورية.
استنتاج
في هذه المقالة ، درسنا الأدوات الأساسية للغة Java: JVM ، JRE ، JDK ، مبدأ ومراحل تنفيذ تعليمات JVM البرمجية ، التجميع ، تنظيم الذاكرة ، بالإضافة إلى مبدأ جامع البيانات المهملة.