Programming Basics SQL HTML CSS JavaScript Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Learn Typing

أقسام الذاكرة في لغة جافا

  • المساحة Heap
  • المساحة Stack
  • المساحة Metaspace

عند تشغيل برنامج مكتوب بلغة جافا تقوم آلة جافا الإفتراضية (JVM) بحجز مساحة من الذاكرة العشوائية لاستهلاكها, و تقسم هذه المساحة إلى عدة أقسام يتم تخزين في كل منها بيانات معينة و لأهداف مختلفة, و لكل منها مساحة محددة تقبل الزيادة, و تقوم آلة جافا الإفتراضية بإدارة بعض الأقسام و تنظفّهم عند الحاجة لتخزين بيانات جديدة, و سنقوم بشرح بعضهم في هذا المقال.


المساحة Heap

تقوم هذه المساحة بتخزين جميع الكائنات التي يتم إنشاؤها في البرنامج بغض النظر عن كيف و أين تم إنشاؤها, و عندما تمتلئ هذه المساحة تقوم آلة جافا الافتراضية بتحفيز جامع القمامة لتنظيف الكائنات التي لم يعد البرنامج بحاجتها حتى يستطيع البرنامج تخزين كائنات جديدة, و عندما لا يجد جامع القمامة ما يمكن إزالته سيحاول توسيع مساحة الـ Heap, وبما أن للـ Heap مساحة كُبرى لا يمكنه تجاوزها ستطلق آلة جافا الافتراضية حينها الخطأ OutOfMemoryError.

عند تشغيل الـ JRE لتقوم بتشغيل برنامج مكتوب بلغة جافا يمكننا تحديد المساحة الأولية التي سيحتلها الـ Heap مباشرة عند تشغيل البرنامج بكتابة المعامل Xms يليه المساحة و ذلك عندما يحتاج البرنامج إلى استهلاك مساحة كبيرة من الذاكرة العشوائية. الفائدة من هذه العملية هي تجاوز عمليات تشغيل جامع القمامة قبل توسيع الـ Heap و التي غالباً ما ستفشل في إيجاد مساحة في حال كان البرنامج يحتاج بالفعل لهكذا مساحة. يمكن أيضاً تحديد مساحة كُبرى لا يمكن للبرنامج تجاوزها بكتابة المعامل Xmx يليه المساحة مع الإشارة إلى أنه عندما لا تقوم بتحديد مساحة كبرى فسيتم تحديدها بناء على نظام التشغيل و مساحة الذاكرة العشوائية المتوفرة و كون النظام 32x أو 64x.

مثال لتشغيل برنامج بمساحة أولية قدرها 256MB ومساحة كبرى قدرها 1GB:

java -jar -Xms256m -Xmx1g MySoftware.jar
java -jar -Xms256m -Xmx1g MySoftware.jar


المساحة Stack

يتم تنفيذ كود جافا دائما داخل Threads, و تقوم آلة جافا الافتراضية بتشغيل Thread واحد أو أكثر أثناء عمل البرنامج.

عند تشغيل البرنامج تقوم آلة جافا الافتراضية بداية بتشغيل أول Thread و المسمى Main Thread و يحدث ذلك بالضبط حين تستدعي الدالة الرئيسية في برنامجنا و التي هي الدالة main().

كل Thread يتم إنشاؤه يتم تخصيص مساحة له تسمى المكدس (Stack) و فيها يتم حفظ البيانات الخاصة بكل دالة نقوم باستدعائها بداخله, و لا يتم مشاركة هذه البيانات بين الـ Threads الآخرين أو حتى بين الدوال الموجودة في نفس المكدس.

لفهم كيف يرى الـ Thread الدوال تخيل معي كيف سينفذ الكود التالي:

public class Test{
public static void main(String[] args){
int x = 5;
Test test = new Test();
method();
System.out.println(x);
}
public void method(){
int y = 10;
System.out.println(y);
}
}
public class Test{ public static void main(String[] args){ int x = 5; Test test = new Test(); method(); System.out.println(x); } public void method(){ int y = 10; System.out.println(y); } }

بداية سيقوم الـ Main Thread بتنفيذ الدالة main() و سيقوم بحجز المساحة التي تحتاجها داخل مساحة المكدس.

بعد أن يبدأ بتنفيذ الكود الموجود داخل الدالة main() سيصل لسطر يتم فيه استدعاء الدالة method(), عندها سيقوم الـ Thread بحجز المساحة التي تحتاجها الدالة method() في المكدس و عند انتهاء تنفيذها سيتم مسح البيانات الخاصة بهذه الدالة من مساحة المكدس و ينتقل التنفيذ إلى الدالة main() لإكمال تنفيذ الأوامر الموجودة فيها. و بعد انتهاء الدالة main() سيتم إزالة المساحة التي استهلكتها من مساحة المكدس.


معلومة تقنية

الطريقة التي يتم فيها حجز المساحة للدوال في هياكل البيانات تسمى بالمكدس (Stack), فالمكدس يقوم بتخزين البيانات بطريقة LIFO التي تعني أنّ آخر من يدخل هو أول من يخرج (Last In First Out), و هذا ما حدث عندما تم تنفيذ الكود السابق فقد دخلت الدالة main()للمكدس ثم دخلت method() و خرجت method() ثم خرجت الدالة main().


ما الذي يتم تخزينه في مساحة المكدس بالضبط؟

عند تعريف و إسناد القيم داخل الدالة للمتغيرات المحلية (Local Variables) التي يمكنها تخزين قيم بدائية (Primitive Data Types) سيتم تخزين قيمة هذا المتغير في مساحة المكدس مثل المتغيرين x و y اللذين قمنا بتعريفهما في المثال السابق.

عند إنشاء كائن كما فعلنا في المثال السابق في الدالة main() سيتم حفظ ذلك الكائن في الـ Heap, و سيتم تخزين مرجع لذلك الكائن داخل المتغير test, و سيُحفظ المرجع فقط في مساحة المكدس الخاصة بالدالة main().

عندما نقوم باستدعاء مئات الدوال في بعض الحالات (مثلاً في حالة استدعاء الدالة لنفسها Recursion) قد تمتلئ مساحة المكدس و ستطلق آلة جافا الافتراضية حينها الخطأ StackOverFlowError.

لتحديد مساحة المكدس يتم كتابة المعامل Xss يليها المساحة.

مثال لتشغيل برنامج بمساحة مكدس قدرها 1MB:

java -jar -Xss1m MySoftware.jar
java -jar -Xss1m MySoftware.jar


المساحة Metaspace

هي مساحة في الذاكرة يتم تخزين الحقول الثابتة (التي نوعها static) بالإضافة للبيانات عن الكلاسات (classes) التي يتم تحميلها و الدوال الخاصة بهم.

في الإصدار 8 من جافا, ظهر هذا القسم من الذاكرة ليستبدل القسم القديم Permanent Generation المحدود الذاكرة و الذي يعرف باختصار PermGen الذي كان يتسبب بالخطأ OutOfMemoryError عندما يمتلئ في البرامج التي تحتاج لتحميل الكثير من الكلاسات.

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

آخر تحديث في 06-01-2024

الكاتب

رامي عبدالله

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

تعليقات 1

أضف تعليق

يجب تسجيل الدخول حتى تتمكن من إضافة تعليق أو رد.

الدورات

أدوات مساعدة

أقسام الموقع

دورات
مقالات كتب مشاريع أسئلة