-Xms و -Xmx في Java: كيفية تسريع JVM وعدم قتل الخادم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا يتباطأ برنامج Java الخاص بك وكيفية إصلاح ذلك باستخدام -Xms و -Xmx؟

\n

هل سبق لك أن قمت بتشغيل تطبيق Java كان يعمل كالساعة في البداية، ثم بدأ يتباطأ بعد ساعة، ثم انهار تمامًا مع خطأ OutOfMemoryError؟ أو على العكس، كان الخادم يستهلك كل ذاكرة الوصول العشوائي ولكنه يستخدم 20% فقط؟ على الأرجح، المشكلة تكمن في إعدادات الكومة — -Xms و -Xmx. هذان المعاملان هما مفتاح التوازن بين الأداء والاستقرار في JVM.

\n

في هذه المقالة، سنشرح ما يفعله -Xms و -Xmx فعليًا، وكيفية اختيارهما بشكل صحيح لتطبيقك، وسنعرض أمثلة على الكود ستساعدك على تجنب الأخطاء الشائعة. هل أنت مستعد؟ هيا بنا!

\n\n

ما هما -Xms و -Xmx؟ تحليل معاملات JVM

\n

باختصار: -Xms يحدد الحجم الأولي للكومة (heap)، بينما -Xmx يحدد الحجم الأقصى. لكن الشيطان، كما هو الحال دائمًا، يكمن في التفاصيل.

\n
    \n
  • -Xms (حجم الكومة الأولي) — مقدار الذاكرة التي سيحجزها JVM عند بدء التشغيل. إذا حددت -Xms512m، فسيقوم الجهاز الظاهري بتخصيص 512 ميجابايت فورًا.
  • \n
  • -Xmx (حجم الكومة الأقصى) — الحد الأعلى الذي يمكن أن تنمو إليه الكومة. على سبيل المثال، -Xmx4g يعني أن JVM لن يستخدم أبدًا أكثر من 4 جيجابايت.
  • \n
\n

لماذا هذا مهم؟ JVM ليست بيئة "مطاطية". إذا خصصت ذاكرة أولية قليلة جدًا (-Xms)، فسيضطر البرنامج إلى الاتصال بجامع القمامة (GC) بشكل متكرر لتوسيع الكومة، مما يبطئ الأداء. إذا قمت بتعيين -Xmx كبير جدًا، فإنك تخاطر باستهلاك كل ذاكرة النظام، وسيبدأ نظام التشغيل في التبديل (swapping) — سينخفض الأداء بشكل كبير.

\n\n

مثال عملي: كيفية ضبط الذاكرة لتطبيق Java

\n

لنتخيل أن لدينا خادم ويب يعمل على Spring Boot يعالج طلبات المستخدمين. بدون إعدادات JVM، سيستخدم القيم الافتراضية (التي تعتمد على إصدار Java وحجم RAM)، مما يؤدي غالبًا إلى مشاكل.

\n

إليك كود بسيط يوضح كيفية التحقق من معاملات الكومة الحالية:

\n
public class MemoryCheck {\n    public static void main(String[] args) {\n        Runtime runtime = Runtime.getRuntime();\n        long maxMemory = runtime.maxMemory(); // -Xmx\n        long initialMemory = runtime.totalMemory(); // حجم الكومة الحالي (قد يكون قريبًا من -Xms)\n        long freeMemory = runtime.freeMemory();\n\n        System.out.println("الذاكرة القصوى (-Xmx): " + maxMemory / (1024 * 1024) + " MB");\n        System.out.println("حجم الكومة الحالي: " + initialMemory / (1024 * 1024) + " MB");\n        System.out.println("الذاكرة الحرة: " + freeMemory / (1024 * 1024) + " MB");\n    }\n}
\n

قم بتشغيل هذا الكود بدون أعلام — سترى القيم الافتراضية. الآن أضف وسائط JVM: -Xms256m -Xmx1g. ستتغير النتيجة بشكل جذري: ستصبح الكومة الأولية 256 ميجابايت، والحد الأقصى 1 جيجابايت.

\n\n

كيفية تمرير المعاملات؟

\n

عند التشغيل من سطر الأوامر:

\n
java -Xms256m -Xmx2g -jar myapp.jar
\n

في بيئة التطوير (IntelliJ IDEA, Eclipse) — في إعدادات تكوين التشغيل. بالنسبة لحاويات Docker — عبر المتغير JAVA_OPTS.

\n\n

تحسين الأداء: كيفية اختيار القيم الصحيحة

\n

القاعدة الذهبية: يجب أن يكون -Xms مساويًا لـ -Xmx في بيئة الإنتاج. لماذا؟ هذا يمنع "قفزات" الذاكرة والاستدعاءات غير الضرورية لجامع القمامة. لن يضيع JVM الوقت في توسيع الكومة، بل سيحصل فورًا على حجم ثابت.

\n

ومع ذلك، هناك تفاصيل دقيقة:

\n