تعمل تطبيقات Java على JVM، لكن هل تعرف تقنية JVM؟ يشرح هذا المقال (الجزء الأول من هذه السلسلة) كيفية عمل جهاز Java الظاهري الكلاسيكي، مثل: إيجابيات وسلبيات الكتابة لمرة واحدة لـ Java، والمحركات عبر الأنظمة الأساسية، وأساسيات جمع البيانات المهملة، وخوارزميات GC الكلاسيكية وتحسين الترجمة. ستتحدث المقالات اللاحقة عن تحسين أداء JVM، بما في ذلك أحدث تصميم لـ JVM - الذي يدعم الأداء وقابلية التوسع لتطبيقات Java المتزامنة للغاية اليوم.
إذا كنت مطورًا، فلا بد أنك واجهت هذا الشعور المميز، فجأة تنتابك ومضة من الإلهام، وتترابط جميع أفكارك، ويمكنك استرجاع أفكارك السابقة من منظور جديد. أنا شخصياً أحب الشعور بتعلم معرفة جديدة. لقد مررت بهذه التجربة عدة مرات أثناء العمل باستخدام تقنية JVM، خاصة مع جمع البيانات المهملة وتحسين أداء JVM. في عالم جافا الجديد هذا، آمل أن أشارككم هذه الإلهامات. أتمنى أن تكون متحمسًا للتعرف على أداء JVM أثناء كتابة هذا المقال.
تمت كتابة هذه السلسلة من المقالات لجميع مطوري Java المهتمين بمعرفة المزيد حول المعرفة الأساسية لـ JVM وما يفعله JVM بالفعل. على مستوى عالٍ، سأناقش جمع البيانات المهملة والسعي اللامتناهي لتحقيق أمان وسرعة الذاكرة المجانية دون التأثير على تشغيل التطبيق. سوف تتعلم الأجزاء الرئيسية من JVM: جمع البيانات المهملة وخوارزميات GC، وتحسين الترجمة، وبعض التحسينات شائعة الاستخدام. سأناقش أيضًا سبب صعوبة ترميز Java وسأقدم لك النصائح حول متى يجب عليك التفكير في اختبار الأداء. أخيرًا، سأتحدث عن بعض الابتكارات الجديدة في JVM وGC، بما في ذلك التركيز على جمع البيانات المهملة Azul's Zing JVM وIBM JVM وOracle's Garbage First (G1).
أتمنى أن تنتهي من قراءة هذه السلسلة بفهم أعمق لطبيعة قيود قابلية التوسع في Java وكيف تجبرنا هذه القيود على إنشاء نشر Java بالطريقة المثلى. نأمل أن يكون لديك حس التنوير وبعض الإلهام الجيد لـ Java: توقف عن قبول هذه القيود وقم بتغييرها! إذا لم تكن من العاملين في مجال البرمجيات مفتوحة المصدر بعد، فقد تشجعك هذه السلسلة على التطوير في هذا المجال.
أداء JVM وتحدي "التجميع مرة واحدة والتشغيل في أي مكان".
لدي أخبار جديدة لأولئك المؤمنين العنيدين بأن منصة Java بطيئة بطبيعتها. عندما أصبحت Java لأول مرة تطبيقًا على مستوى المؤسسة، كانت مشكلات أداء Java التي تم انتقاد JVM بسببها موجودة بالفعل منذ أكثر من عشر سنوات، ولكن هذا الاستنتاج أصبح الآن قديمًا. صحيح أنه إذا قمت بتشغيل مهام ثابتة وحتمية بسيطة على منصات تطوير مختلفة اليوم، فستجد على الأرجح أن استخدام التعليمات البرمجية المُحسّنة للجهاز سيؤدي بشكل أفضل من استخدام أي بيئة افتراضية، ضمن نفس JVM. ومع ذلك، فقد تحسن أداء Java بشكل كبير في السنوات العشر الماضية. أدى الطلب في السوق والنمو في صناعة Java إلى ظهور عدد قليل من خوارزميات جمع البيانات المهملة، وابتكارات التجميع الجديدة، ومجموعة من الاستدلالات والتحسينات التي ساهمت في تطوير تقنية JVM. سأغطي بعضًا منها في الفصول القادمة.
يعد الجمال الفني لـ JVM أيضًا التحدي الأكبر الذي يواجهه: لا شيء يمكن اعتباره تطبيق "تجميع مرة واحدة وتشغيل في أي مكان". بدلاً من التحسين لحالة استخدام واحدة، أو تطبيق واحد، أو تحميل مستخدم محدد، يقوم JVM باستمرار بتتبع ما يفعله تطبيق Java حاليًا وتحسينه وفقًا لذلك. تؤدي هذه العملية الديناميكية إلى سلسلة من المشكلات الديناميكية. لا يعتمد المطورون الذين يعملون على JVM على التجميع الثابت ومعدلات التخصيص المتوقعة عند تصميم الابتكارات (على الأقل ليس عندما نطالب بالأداء في بيئات الإنتاج).
سبب أداء JVM
في عملي المبكر، أدركت أن جمع البيانات المهملة كان من الصعب جدًا "حله"، وكنت دائمًا مفتونًا بأجهزة JVM وتكنولوجيا البرامج الوسيطة. بدأ شغفي بأجهزة JVM عندما كنت ضمن فريق JRockit، حيث قمت ببرمجة طريقة جديدة لتعليم نفسي وتصحيح أخطاء خوارزميات جمع البيانات المهملة بنفسي (انظر الموارد). بدأ هذا المشروع (الذي تحول إلى ميزة تجريبية لـ JRockit وأصبح الأساس لخوارزمية جمع البيانات المهملة الحتمية) رحلتي إلى تقنية JVM. لقد عملت في BEA Systems وIntel وSun وOracle (نظرًا لأن Oracle استحوذت على BEA Systems، عملت في Oracle لفترة وجيزة). ثم انضممت إلى فريق Azul Systems لإدارة Zing JVM، والآن أعمل في Cloudera.
قد تحقق التعليمات البرمجية المحسّنة للآلة أداءً أفضل (ولكن على حساب المرونة)، ولكن هذا ليس سببًا لوزنها لتطبيقات المؤسسات ذات التحميل الديناميكي والوظائف المتغيرة بسرعة. من أجل مزايا Java، تكون معظم الشركات أكثر استعدادًا للتضحية بالأداء الذي لا يكاد يكون مثاليًا والذي توفره التعليمات البرمجية المُحسّنة للآلة.
1. سهولة البرمجة وتطوير الوظائف (بمعنى وقت أقصر للاستجابة للسوق)
2. احصل على مبرمجين ذوي خبرة
3. استخدم واجهات برمجة تطبيقات Java والمكتبات القياسية للتطوير بشكل أسرع
4. قابلية النقل - لا حاجة لإعادة كتابة تطبيقات Java لمنصات جديدة
من كود جافا إلى كود البايت
باعتبارك مبرمج Java، ربما تكون على دراية بتشفير تطبيقات Java وتجميعها وتنفيذها. مثال: لنفترض أن لديك برنامجًا (MyApp.java) وتريد تشغيله الآن. لتنفيذ هذا البرنامج، يجب عليك أولاً تجميعه باستخدام javac (لغة Java الثابتة لمترجم كود البايت المدمج في JDK). استنادًا إلى كود Java، يقوم javac بإنشاء الكود الثانوي المقابل القابل للتنفيذ وحفظه في ملف الفئة بالاسم نفسه: MyApp.class. بعد تجميع كود Java في bytecode، يمكنك بدء ملف الفئة القابل للتنفيذ من خلال أمر java (من خلال سطر الأوامر أو البرنامج النصي لبدء التشغيل، دون استخدام خيار بدء التشغيل) لتشغيل التطبيق الخاص بك. بهذه الطريقة، يتم تحميل فصلك في وقت التشغيل (أي تشغيل جهاز Java الظاهري)، ويبدأ تنفيذ البرنامج.
هذا هو ما ينفذه كل تطبيق على السطح، ولكن الآن دعونا نستكشف ما يحدث بالضبط عند تنفيذ أمر جافا. ما هو جهاز جافا الظاهري؟ يتفاعل معظم المطورين مع JVM من خلال التصحيح المستمر - ويعرف أيضًا باسم تحديد خيارات بدء التشغيل وتعيين القيمة لجعل برامج Java الخاصة بك تعمل بشكل أسرع مع تجنب أخطاء "نفاد الذاكرة" سيئة السمعة. ولكن، هل تساءلت يومًا لماذا نحتاج إلى JVM لتشغيل تطبيقات Java في المقام الأول؟
ما هو جهاز جافا الظاهري؟
ببساطة، JVM عبارة عن وحدة برمجية تنفذ الكود الثانوي لتطبيق Java وتحول الكود الثانوي إلى تعليمات خاصة بالأجهزة ونظام التشغيل. من خلال القيام بذلك، يسمح JVM بتنفيذ برنامج Java في بيئة مختلفة بعد كتابته لأول مرة، دون الحاجة إلى إجراء تغييرات على الكود الأصلي. تعد قابلية نقل Java هي المفتاح للغة تطبيق المؤسسة: لا يحتاج المطورون إلى إعادة كتابة كود التطبيق لمنصات مختلفة لأن JVM يعتني بالترجمة وتحسين النظام الأساسي.
JVM هي في الأساس بيئة تنفيذ افتراضية تعمل كآلة تعليمات للرمز الثانوي وتستخدم لتخصيص مهام التنفيذ وتنفيذ عمليات الذاكرة من خلال التفاعل مع الطبقة الأساسية.
يعتني JVM أيضًا بإدارة الموارد الديناميكية لتشغيل تطبيقات Java. وهذا يعني أنه يتقن تخصيص الذاكرة وتحريرها، ويحافظ على نموذج ترابط متسق على كل نظام أساسي، وينظم التعليمات القابلة للتنفيذ حيث يتم تنفيذ التطبيق بطريقة مناسبة لبنية وحدة المعالجة المركزية. يحرر JVM المطورين من تتبع المراجع إلى الكائنات والمدة التي يحتاجونها للتواجد في النظام. وبالمثل، فإنه لا يتطلب منا إدارة وقت تحرير الذاكرة - وهي نقطة ألم في اللغات غير الديناميكية مثل C.
يمكنك التفكير في JVM كنظام تشغيل مصمم خصيصًا لتشغيل Java؛ وتتمثل مهمته في إدارة بيئة التشغيل لتطبيقات Java. JVM هي في الأساس بيئة تنفيذ افتراضية تتفاعل مع البيئة الأساسية كجهاز تعليمات بايت كود لتخصيص مهام التنفيذ وتنفيذ عمليات الذاكرة.
نظرة عامة على مكونات JVM
هناك العديد من المقالات المكتوبة حول الأجزاء الداخلية لـ JVM وتحسين الأداء. كأساس لهذه السلسلة، سأقوم بتلخيص وإلقاء نظرة عامة على مكونات JVM. هذه النظرة العامة الموجزة مفيدة بشكل خاص للمطورين الجدد في JVM وستجعلك ترغب في معرفة المزيد حول المناقشات الأكثر تعمقًا التي تتبع ذلك.
من لغة إلى أخرى - حول مترجمي جافا
يأخذ المترجم لغة واحدة كمدخل ثم يقوم بإخراج بيان آخر قابل للتنفيذ. لدى مترجم Java مهمتان رئيسيتان:
1. جعل لغة Java أكثر قابلية للنقل ولم تعد بحاجة إلى التثبيت على نظام أساسي محدد عند الكتابة لأول مرة؛
2. تأكد من إنتاج تعليمات برمجية صالحة قابلة للتنفيذ لمنصة معينة.
يمكن أن تكون المترجمات ثابتة أو ديناميكية. مثال على التجميع الثابت هو javac. يأخذ رمز Java كمدخل ويحوله إلى رمز بايت (لغة يتم تنفيذها في جهاز Java الظاهري). يقوم المترجم الثابت بتفسير كود الإدخال مرة واحدة ويخرج نموذجًا قابلاً للتنفيذ، والذي سيتم استخدامه عند تنفيذ البرنامج. نظرًا لأن الإدخال ثابت، فسترى دائمًا نفس النتيجة. فقط إذا قمت بتعديل الكود الأصلي وإعادة ترجمته، فسوف ترى مخرجات مختلفة.
تقوم المترجمات الديناميكية ، مثل مترجمات Just-In-Time (JIT)، بتحويل لغة إلى أخرى ديناميكيًا، مما يعني أنها تفعل ذلك أثناء تنفيذ التعليمات البرمجية. يتيح لك برنامج التحويل البرمجي JIT جمع أو إنشاء تحليلات وقت التشغيل (عن طريق إدراج أعداد الأداء)، باستخدام قرارات المترجم، باستخدام بيانات البيئة المتوفرة. يمكن للمترجم الديناميكي تنفيذ تسلسلات تعليمات أفضل أثناء عملية التحويل البرمجي إلى لغة ما، واستبدال سلسلة من التعليمات بأخرى أكثر كفاءة، وحتى التخلص من العمليات الزائدة عن الحاجة. بمرور الوقت، ستجمع المزيد من بيانات تكوين التعليمات البرمجية وتتخذ قرارات تجميع أكثر وأفضل؛ العملية برمتها هي ما نسميه عادةً تحسين التعليمات البرمجية وإعادة ترجمتها.
يمنحك التجميع الديناميكي ميزة التكيف مع التغييرات الديناميكية بناءً على السلوك، أو التحسينات الجديدة مع زيادة عدد تحميلات التطبيق. هذا هو السبب في أن المترجمين الديناميكيين مثاليون لعمليات Java. تجدر الإشارة إلى أن المترجم الديناميكي يطلب هياكل البيانات الخارجية وموارد الخيوط وتحليل دورة وحدة المعالجة المركزية وتحسينها. كلما كان التحسين أعمق، زادت الموارد التي ستحتاجها. ومع ذلك، في معظم البيئات، تضيف الطبقة العليا القليل جدًا إلى الأداء - أداء أسرع من 5 إلى 10 مرات من التفسير النقي.
يؤدي التخصيص إلى جمع البيانات المهملة
يتم تخصيصها في كل مؤشر ترابط بناءً على "مساحة عنوان الذاكرة المخصصة لعملية Java"، أو تسمى كومة Java، أو تسمى الكومة مباشرة. في عالم Java، يعد التخصيص ذو الترابط المفرد أمرًا شائعًا في تطبيقات العميل. ومع ذلك، فإن التخصيص أحادي الترابط ليس مفيدًا في تطبيقات المؤسسات وخوادم عبء العمل لأنه لا يستفيد من التوازي في البيئات متعددة النواة الحالية.
يفرض تصميم التطبيق المتوازي أيضًا على JVM التأكد من أن مؤشرات الترابط المتعددة لا تخصص نفس مساحة العنوان في نفس الوقت. يمكنك التحكم في ذلك عن طريق وضع قفل على المساحة المخصصة بالكامل. لكن هذه التقنية (التي تسمى غالبًا قفل الكومة) كثيفة الأداء للغاية، ويمكن أن يؤثر الاحتفاظ بالسلاسل أو وضعها في قائمة الانتظار على استخدام الموارد وأداء تحسين التطبيق. الشيء الجيد في الأنظمة متعددة النواة هو أنها تخلق حاجة إلى مجموعة متنوعة من الأساليب الجديدة لمنع الاختناقات ذات الخيوط المفردة أثناء تخصيص الموارد والتسلسل.
تتمثل الطريقة الشائعة في تقسيم الكومة إلى أجزاء، حيث يكون لكل قسم حجم معقول للتطبيق - من الواضح أنه يحتاج إلى ضبط، وتختلف معدلات التخصيص وأحجام الكائنات بشكل كبير بين التطبيقات، كما يختلف عدد سلاسل العمليات نفسها أيضًا. المخزن المؤقت للتخصيص المحلي لمؤشر الترابط (TLAB)، أو في بعض الأحيان المنطقة المحلية لمؤشر الترابط (TLA)، هو قسم متخصص يمكن للسلاسل تخصيصه بحرية دون الإعلان عن قفل كومة كاملة. عندما تكون المنطقة ممتلئة، تكون الكومة ممتلئة، مما يعني أنه لا توجد مساحة حرة كافية على الكومة لوضع الكائنات، ويجب تخصيص المساحة. عند امتلاء الكومة، ستبدأ عملية جمع البيانات المهملة.
شظايا
يؤدي استخدام TLABs لالتقاط الاستثناءات إلى تجزئة الكومة لتقليل كفاءة الذاكرة. إذا كان التطبيق غير قادر على زيادة مساحة TLAB أو تخصيصها بالكامل عند تخصيص الكائنات، فهناك خطر أن تكون المساحة صغيرة جدًا بحيث لا يمكن إنشاء كائنات جديدة. تعتبر هذه المساحة الحرة "تجزئة". إذا احتفظ التطبيق بمرجع إلى الكائن ثم قام بتخصيص المساحة المتبقية، فستكون المساحة خالية في النهاية لفترة طويلة.
يحدث التجزئة عندما تتناثر الأجزاء عبر الكومة - مما يؤدي إلى إهدار مساحة الكومة من خلال أقسام صغيرة من مساحة الذاكرة غير المستخدمة. تخصيص مساحة TLAB "خاطئة" للتطبيق الخاص بك (فيما يتعلق بحجم الكائن، وحجم الكائن المختلط، ونسبة الاحتفاظ بالمرجع) هو سبب زيادة تجزئة الكومة. أثناء تشغيل التطبيق، يزيد عدد الأجزاء ويشغل مساحة في الكومة. يؤدي التجزئة إلى تدهور الأداء ولا يتمكن النظام من تخصيص ما يكفي من مؤشرات الترابط والكائنات للتطبيقات الجديدة. ثم سيواجه مجمّع البيانات المهملة صعوبة في منع استثناءات نفاد الذاكرة.
يتم إنشاء نفايات TLAB أثناء العمل. إحدى الطرق لتجنب التجزئة كليًا أو مؤقتًا هي تحسين مساحة TLAB في كل عملية أساسية. الأسلوب النموذجي لهذا الأسلوب هو أنه طالما أن التطبيق لديه سلوك التخصيص، فإنه يحتاج إلى إعادة ضبطه. يمكن تحقيق ذلك من خلال خوارزميات JVM المعقدة. هناك طريقة أخرى تتمثل في تنظيم أقسام الكومة لتحقيق تخصيص أكثر كفاءة للذاكرة. على سبيل المثال، يمكن لـ JVM تنفيذ قوائم مجانية، والتي ترتبط معًا كقائمة من كتل الذاكرة المجانية ذات حجم معين. يتم توصيل كتلة الذاكرة الحرة المتجاورة بكتلة ذاكرة أخرى متجاورة بنفس الحجم، وبالتالي إنشاء عدد صغير من القوائم المرتبطة، ولكل منها حدودها الخاصة. في بعض الحالات، تؤدي القوائم المجانية إلى تخصيص أفضل للذاكرة. يمكن للخيوط تخصيص الكائنات في كتل ذات حجم مماثل، مما قد يؤدي إلى إنشاء تجزئة أقل مما لو كنت تعتمد فقط على TLABs ذات الحجم الثابت.
التوافه جي سي
كان لدى بعض جامعي القمامة الأوائل عدة أجيال قديمة، ولكن وجود أكثر من جيلين قديمين من شأنه أن يؤدي إلى زيادة النفقات العامة عن القيمة. هناك طريقة أخرى لتحسين التخصيصات وتقليل التجزئة وهي إنشاء ما يسمى بالجيل الشاب، وهو عبارة عن مساحة كومة مخصصة لتخصيص كائنات جديدة. الكومة المتبقية تصبح ما يسمى بالجيل القديم. يتم استخدام الجيل القديم لتخصيص الكائنات طويلة العمر، والتي من المفترض أن تكون موجودة لفترة طويلة، بما في ذلك الكائنات التي ليست مجمعة من البيانات المهملة أو كائنات كبيرة. من أجل فهم طريقة التخصيص هذه بشكل أفضل، نحتاج إلى التحدث عن بعض المعرفة حول جمع البيانات المهملة.
جمع البيانات المهملة وأداء التطبيق
مجموعة البيانات المهملة هي أداة تجميع البيانات المهملة في JVM لتحرير ذاكرة الكومة المشغولة التي لم يتم الرجوع إليها. عند تشغيل مجموعة البيانات المهملة لأول مرة، يتم الاحتفاظ بجميع مراجع الكائنات، ويتم تحرير المساحة التي تشغلها المراجع السابقة أو إعادة تخصيصها. بعد جمع كل الذاكرة القابلة للاسترداد، تنتظر المساحة ليتم الاستيلاء عليها وتخصيصها مرة أخرى لكائنات جديدة.
لا يمكن لأداة تجميع البيانات المهملة مطلقًا إعادة تعريف كائن مرجعي، حيث أن القيام بذلك سيؤدي إلى كسر المواصفات القياسية لـ JVM. الاستثناء لهذه القاعدة هو مرجع ضعيف أو ضعيف يمكن اكتشافه إذا كانت ذاكرة أداة تجميع البيانات المهملة على وشك النفاد. أوصي بشدة بمحاولة تجنب المراجع الضعيفة، لأن غموض مواصفات Java يؤدي إلى تفسيرات خاطئة وأخطاء في الاستخدام. علاوة على ذلك، تم تصميم Java لإدارة الذاكرة الديناميكية، لأنك لا تحتاج إلى التفكير في متى وأين سيتم تحرير الذاكرة.
أحد التحديات التي تواجه أداة تجميع البيانات المهملة هو تخصيص الذاكرة بطريقة لا تؤثر على التطبيقات قيد التشغيل. إذا لم تقم بجمع البيانات المهملة قدر الإمكان، فسوف يستهلك تطبيقك الذاكرة؛ وإذا قمت بالتجميع كثيرًا، فسوف تفقد الإنتاجية ووقت الاستجابة، مما سيكون له تأثير سيء على التطبيق قيد التشغيل.
خوارزمية جي سي
هناك العديد من خوارزميات جمع البيانات المهملة المختلفة. سيتم مناقشة عدة نقاط بعمق لاحقًا في هذه السلسلة. على أعلى مستوى، الطريقتان الرئيسيتان لجمع البيانات المهملة هما العد المرجعي وتتبع جامعي البيانات.
يقوم مُجمع عد المراجع بتتبع عدد المراجع التي يشير إليها الكائن. عندما يصل مرجع الكائن إلى 0، سيتم استعادة الذاكرة على الفور، وهي إحدى مزايا هذا الأسلوب. تكمن صعوبة أسلوب حساب المراجع في بنية البيانات الدائرية والحفاظ على تحديث جميع المراجع في الوقت الفعلي.
يقوم مجمع التتبع بوضع علامات على الكائنات التي لا تزال قيد الرجوع إليها، ويستخدم الكائنات المحددة لمتابعة كافة الكائنات المشار إليها ووضع علامة عليها بشكل متكرر. عندما يتم وضع علامة على كافة الكائنات التي لا تزال مرجعية على أنها "مباشرة"، سيتم استعادة كل المساحة غير المميزة. يدير هذا الأسلوب هياكل البيانات الحلقية، ولكن في كثير من الحالات، يجب على المجمع الانتظار حتى اكتمال جميع العلامات قبل استعادة الذاكرة غير المرجعية.
هناك طرق مختلفة للقيام بالطريقة المذكورة أعلاه. أشهر الخوارزميات هي خوارزميات الوسم أو النسخ، الخوارزميات المتوازية أو المتزامنة. وسأناقش هذه في مقال لاحق.
بشكل عام، معنى جمع البيانات المهملة هو تخصيص مساحة العنوان للكائنات الجديدة والقديمة في الكومة. "الكائنات القديمة" هي كائنات نجت من العديد من مجموعات البيانات المهملة. استخدم الجيل الجديد لتخصيص الكائنات الجديدة والجيل القديم للكائنات القديمة، مما يؤدي إلى تقليل التجزئة عن طريق إعادة تدوير الكائنات قصيرة العمر التي تشغل الذاكرة بسرعة، كما يقوم أيضًا بتجميع الكائنات طويلة العمر معًا ووضعها في عناوين الجيل القديم. كل هذا يقلل من التجزئة بين الكائنات طويلة العمر ويحفظ ذاكرة الكومة من التجزئة. التأثير الإيجابي للجيل الجديد هو أنه يؤخر المجموعة الأكثر تكلفة من كائنات الجيل القديم، ويمكنك إعادة استخدام نفس المساحة للكائنات سريعة الزوال. (سيكون تجميع المساحة القديمة أكثر تكلفة لأن الكائنات طويلة العمر ستحتوي على المزيد من المراجع وتتطلب المزيد من عمليات الاجتياز.)
الخوارزمية الأخيرة الجديرة بالذكر هي الضغط، وهي طريقة لإدارة تجزئة الذاكرة. يقوم الضغط بشكل أساسي بنقل الكائنات معًا لتحرير مساحة ذاكرة متجاورة أكبر. إذا كنت على دراية بتجزئة القرص والأدوات التي تتعامل معها، فستجد أن الضغط مشابه جدًا له، باستثناء أن هذا يعمل في ذاكرة كومة Java. سأناقش الضغط بالتفصيل لاحقًا في السلسلة.
ملخص: مراجعة ويسلط الضوء
يسمح JVM بإمكانية النقل (البرنامج مرة واحدة، والتشغيل في أي مكان) وإدارة الذاكرة الديناميكية، وجميع الميزات الرئيسية لمنصة Java التي تساهم في شعبيتها وزيادة إنتاجيتها.
في المقالة الأولى عن أنظمة تحسين أداء JVM، شرحت كيف يقوم المترجم بتحويل الكود الثانوي إلى لغة التعليمات للنظام الأساسي المستهدف ويساعد على تحسين تنفيذ برامج Java ديناميكيًا. تتطلب التطبيقات المختلفة مترجمين مختلفين.
كما قمت أيضًا بتغطية تخصيص الذاكرة وجمع البيانات المهملة بشكل موجز، وكيفية ارتباطها بأداء تطبيق Java. في الأساس، كلما زادت سرعة ملء الكومة وتشغيل جمع البيانات المهملة بشكل متكرر، زاد معدل استخدام تطبيق Java الخاص بك. أحد التحديات التي تواجه أداة تجميع البيانات المهملة هو تخصيص الذاكرة بطريقة لا تؤثر على التطبيق قيد التشغيل، ولكن قبل نفاد ذاكرة التطبيق. سنناقش في المقالات المستقبلية جمع البيانات المهملة التقليدية والجديدة وتحسينات أداء JVM بمزيد من التفاصيل.