إدارة الذاكرة في Java

⚡ ملخص ذكي

إدارة الذاكرة في Java يشرح كيف تقسم آلة جافا الافتراضية ذاكرة وقت التشغيل عبر المكدس والكومة Codeوالمناطق الثابتة، وكيفية تدفق مراجع الكائنات أثناء استدعاءات الأساليب، وكيف يقوم جامع البيانات المهملة باستعادة الكائنات التي لا يمكن الوصول إليها حتى تظل التطبيقات مستقرة وخالية من تسرب الذاكرة.

  • 🧠 تخطيط ذاكرة JVM: Java يتم تقسيم الذاكرة إلى كومة للكائنات، ومكدس لإطارات الأساليب والمتغيرات المحلية، بالإضافة إلى مناطق مخصصة لرمز البايت والبيانات الثابتة.
  • 📚 المكدس مقابل الكومة: تتبع إطارات المكدس ترتيب Last-In-First-Out وتخزن العناصر الأولية والمراجع، بينما تحتوي الكومة على كل كائن تم إنشاؤه باستخدام عامل التشغيل الجديد.
  • ♻️ جمع القمامة: جامع القمامة tracتوفر إمكانية الوصول من خلال سلاسل المراجع وتستعيد الذاكرة تلقائيًا من الكائنات التي لا يمكن لأي مؤشر ترابط الوصول إليها.
  • هواة جمع التحف الحديثة: تعتمد أحمال العمل الإنتاجية بشكل متزايد على G1 و ZGC و Shenandoah لجمع البيانات مع فترات توقف منخفضة عبر أكوام متعددة الجيجابايت.
  • 🧪 مثال عملي: يُظهر شرح تفصيلي خطوة بخطوة لفئة الطالب متى تصبح المراجع مؤهلة للتجميع وكيف يؤدي إلغاء المراجع إلى تحرير الكائن الأساسي.

إدارة الذاكرة في Java

ما هي ذاكرة المكدس في Java?

ذاكرة المكدس في Java تُعدّ Stack منطقة في ذاكرة JVM تُخزّن إطارات الدوال والمتغيرات المحلية ومتغيرات المراجع لكل خيط. ويتم الوصول إلى Stack دائمًا بترتيب Last-In-First-Out، بحيث تكون الدالة التي تم استدعاؤها مؤخرًا في الأعلى، ويتم دفع متغيراتها المحلية وسحبها مع الإطار.

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

ما هي ذاكرة الكومة في Java?

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

الكومة هي المنطقة التي يديرها جامع البيانات المهملة. تقسم آلات جافا الافتراضية الحديثة HotSpot الكومة إلى جيل صغير للكائنات قصيرة العمر وجيل قديم للكائنات طويلة العمر، مع تخزين بيانات تعريف الفئة في منطقة أصلية منفصلة تسمى ميتا سبيس.

تخصيص الذاكرة في Java

تخصيص الذاكرة في Java هي العملية التي تقوم بها آلة جافا الافتراضية (JVM) بتخصيص مناطق ذاكرة افتراضية للمتغيرات ونسخ الفئات والهياكل أثناء تنفيذ البرنامج. لا يتم تخصيص الذاكرة للكائن عند تعريفه، بل يتم إنشاء مرجع فقط. يتم تخصيص الكائن فعليًا من خلال عامل التشغيل new، لذا فإن كل كائن موجود في الذاكرة الديناميكية (Heap).

استخدم Java ينقسم تخصيص الذاكرة إلى الأقسام التالية:

  1. كومة
  2. كومة
  3. Code
  4. ساكن

يُعد تقسيم الذاكرة هذا ضرورياً للإدارة الفعالة لوقت التشغيل.

  • استخدم Code يحتوي هذا القسم على ما قمت بتجميعه بايت كود.
  • استخدم كومة متاجر الأقسام الأساليب، والمتغيرات المحلية، والمتغيرات المرجعية.
  • استخدم كومة يحتوي القسم الأجسام وقد تحتوي أيضًا على متغيرات مرجعية محفوظة كحقول مثيل.
  • استخدم ساكن القسم يحتوي البيانات الثابتة والأساليب الثابتة يتم مشاركتها عبر جميع الحالات.

الفرق بين المتغير المحلي ومتغير المثيل

يساعد فهم مكان وجود كل نوع من أنواع المتغيرات في JVM على شرح سلوك المكدس والكومة. المتغيرات الخاصة أعلن داخل فئة ولكن خارج أي دالةوهو موجود في الكومة كجزء من كائنه.

class Student{ 
int num; // num is instance variable 
public void showData{}

A متغير محلي أعلن داخل دالة، بما في ذلك وسائط الدالة، وتعيش على المكدس داخل الإطار النشط.

public void sum(int a){

int x = a + 3;

// a, x are local variables

}

الفرق بين المكدس والكومة

يُعالج كلٌّ من المكدس والكومة مشكلاتٍ مختلفة داخل آلة جافا الافتراضية. يُتيح المكدس لكل خيط تخصيصًا سريعًا ومحددًا للبيانات قصيرة الأجل المرتبطة بنطاق الدالة، بينما تُوفّر الكومة منطقةً مشتركةً للكائنات طويلة الأجل التي يُمكن لأي خيط الرجوع إليها. يُلخّص الفيديو القصير أدناه الفرق بينهما قبل الشرح العملي الذي يليه.

انقر اضغط هنا إذا لم يكن من الممكن الوصول إلى الفيديو

لمعرفة كيفية تعاون المكدس والكومة، ضع في اعتبارك طريقة رئيسية تستدعي الطريقة m1.

public void m1{
int x = 20;
}

في مكدس JVM، يتم إنشاء إطار للطريقة m1.

Java كومة وكومة

يتم أيضًا إنشاء المتغير x في m1 في إطار m1 على المكدس، كما هو موضح في الصورة أدناه.

Java كومة وكومة

ثم يقوم الأسلوب m1 باستدعاء الأسلوب m2. في المكدس، يتم إنشاء إطار جديد لـ m2 فوق إطار m1.

Java كومة وكومة

Java كومة وكومة

يتم أيضًا إنشاء المتغيرات المحلية b و c داخل إطار m2 على المكدس.

public void m2(int b){
boolean c;
}

بعد ذلك، يستدعي m2 الطريقة m3. ومرة ​​أخرى، يتم إنشاء إطار لـ m3 في أعلى المكدس، كما هو موضح أدناه.

Java كومة وكومة

Java كومة وكومة

لنفترض الآن أن الدالة m3 تنشئ كائنًا من فئة Account، والذي يحتوي على اثنين متغيرات سريعة إنت ص و إنت ف.

class Account {
    int p;
    int q;
}

إليكم رمز الطريقة m3.

public void m3(){
    Account ref = new Account();
    // more code
}

تقوم العبارة new Account() بإنشاء كائن من نوع Account في الذاكرة الديناميكية (Heap).

Java كومة وكومة

يتم إنشاء متغير المرجع ref على المكدس داخل الإطار الخاص بـ m3.

Java كومة وكومة

يجعل عامل التعيين متغير المرجع يشير إلى الكائن الموجود في الذاكرة الديناميكية (Heap).

Java كومة وكومة

بمجرد اكتمال تنفيذ الطريقة، يعود التحكم إلى الطريقة المستدعِية، وهي في هذه الحالة الطريقة m2.

Java كومة وكومة

يتم إخراج إطار الطريقة m3 من المكدس.

Java كومة وكومة

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

Java كومة وكومة

بمجرد انتهاء تنفيذ الدالة m2، يتم إزالتها من مكدس الاستدعاءات وتصبح جميع متغيراتها غير متاحة. ويحدث الشيء نفسه مع الدالة m1، وفي النهاية يعود التحكم إلى الدالة الرئيسية.

ماذا لو كان الكائن يحتوي على مرجع آخر كمتغير مثيل له؟

public static void main(String args[]) {
    A parent = new A();
    // more code
}
class A {
    B child = new B();
    int e;
}
class B {
    int c;
    int d;
}

في هذه الحالة، يوجد المتغير المرجعي child في الذاكرة كجزء من الكائن A، ويشير بدوره إلى الكائن B الخاص به، كما هو موضح أدناه.

Java كومة وكومة

ما هو جمع القمامة في Java?

جمع القمامة في Java هي العملية التي تُدير بها آلة جافا الافتراضية (JVM) الذاكرة تلقائيًا. يقوم جامع البيانات المهملة (Garbage Collector) بالعثور على الكائنات التي لم تعد قابلة للوصول إليها من أي مرجع نشط، ثم يستعيد ذاكرتها. يتم تخصيص الذاكرة الديناميكية من خلال عامل التشغيل new، وتبقى الذاكرة مُخصصة حتى يتوقف البرنامج عن الاحتفاظ بأي مرجع للكائن.

عندما لا تبقى أي مراجع، يُعتبر الكائن غير مطلوب، ويمكن استعادة الذاكرة التي يشغلها. لا توجد حاجة صريحة لتدمير الكائن لأن Java يتولى جامع البيانات المهملة عملية إلغاء التخصيص تلقائيًا.

تُعرف التقنية الكامنة وراء ذلك باسم جمع القمامةالبرامج التي تفشل في تحرير الذاكرة تتعطل في النهاية عندما لا يتبقى شيء لتخصيصه. ويُقال إن هذه البرامج تعاني من خلل في الذاكرة. تسريبات الذاكرة. جمع القمامة في Java يتم تشغيله تلقائيًا طوال فترة البرنامج، مما يزيل عبء إلغاء التخصيص اليدوي ويقلل من خطر التسريبات.

في لغة C، على النقيض من ذلك، يكون المبرمج مسؤولاً عن تحرير الذاكرة المخصصة ديناميكيًا من خلال الدالة free(). هذا هو المكان الذي Java توفر إدارة الذاكرة ميزة قوية.

تُوفر بيئات JVM الحديثة لتقنية HotSpot عدة مُجمّعات قمامة مُحسّنة لأحمال عمل مُختلفة. يستهدف مُجمّع القمامة الافتراضي G1 تحقيق توازن بين الإنتاجية وأوقات التوقف المؤقت على أكوام الذاكرة الضخمة (عدة غيغابايت). بينما يهدف كل من ZGC و Shenandoah إلى تحقيق توقفات مؤقتة في أقل من جزء من الألف من الثانية على أكوام الذاكرة الضخمة جدًا، مما يجعلهما فيtracيُعد اختيار المُجمِّع المناسب وضبط أحجام الجيل الصغير والجيل القديم ومساحة التخزين مهارة أساسية للخدمات الحساسة للتأخير. Java عمل أدائي.

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

مثال: للتعرف على آلية تجميع البيانات المهملة في Java

يوضح هذا الدليل متى تصبح المراجع مؤهلة لجمع البيانات المهملة داخل برنامج بسيط.

الخطوة 1) انسخ الكود التالي إلى المحرر.

class Student{
int a;
int b;
  public void setData(int c,int d){
    a=c;
    b=d;
  }
  public void showData(){
    System.out.println("Value of a = "+a);
    System.out.println("Value of b = "+b);
  }
  public static void main(String args[]){
    Student s1 = new Student();
    Student s2 = new Student();
    s1.setData(1,2);
    s2.setData(3,4);
    s1.showData();
    s2.showData();
    //Student s3;
    //s3=s2;
    //s3.showData();
    //s2=null;
    //s3.showData();
    //s3=null;
    //s3.showData();
  }
}

الخطوة 2) احفظ الكود وقم بتجميعه وتشغيله. كما هو موضح في الرسم التخطيطي، يتم إنشاء كائنين ومتغيرين مرجعيين.

 آلية جمع القمامة

الخطوة 3) قم بإلغاء التعليق على الأسطر 20 و 21 و 22. احفظ الكود وقم بتجميعه وتشغيله.

الخطوة 4) كما هو موضح في الرسم البياني أدناه، يشير متغيران مرجعيان الآن إلى نفس الكائن.

آلية جمع القمامة

الخطوة 5) قم بإلغاء التعليق على السطرين 23 و 24. احفظ الكود وقم بتجميعه وتشغيله.

الخطوة 6) كما هو موضح أدناه، يصبح s2 فارغًا، لكن s3 لا يزال يشير إلى الكائن، لذلك فإن الكائن ليس مؤهلًا بعد لجمع البيانات المهملة.

 آلية جمع القمامة

الخطوة 7) قم بإلغاء التعليق على السطرين 25 و 26. احفظ الكود وقم بتجميعه وتشغيله.

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

 تعلم جامع القمامة

كيفية حذف عنصر في Java?

Java لا يوفر عامل حذف يدوي، لذا فإن النهج القياسي هو إزالة كل مرجع للكائن حتى يتمكن جامع البيانات المهملة من استعادته.

1) لجعل كائن ما مؤهلاً لجمع البيانات المهملة، قم بتعيين كل متغير مرجعي يشير إليه إلى قيمة فارغة (null).

2) الأنواع الأولية ليست كائنات، لذا لا يمكن إسناد قيمة فارغة لها. يتم استعادة مساحة التخزين الخاصة بها تلقائيًا عند إزالة إطار المكدس المحيط بها.

كيفية حذف كائن في Java

الأسئلة الشائعة

يخزن المكدس إطارات الأساليب والمتغيرات المحلية والمراجع بترتيب "آخر ما يدخل أول ما يخرج" لكل سلسلة عمليات. أما الكومة فتخزن جميع الكائنات التي تم إنشاؤها باستخدام new، وهي مشتركة بين سلاسل العمليات، ولهذا السبب يديرها جامع البيانات المهملة.

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

يحتفظ الجيل الشاب بالكائنات قصيرة العمر في مساحات عدن والناجين. أما الجيل القديم فيحتفظ بالكائنات التي تبقى بعد عمليات تجميع متعددة. مساحة الذاكرة الدائمة هي منطقة ذاكرة أصلية تخزن بيانات تعريف الفئات، وقد حلت محل مساحة PermGen الأقدم. Java 8.

يُعد G1 الخيار الافتراضي ويناسب معظم أحمال العمل على أكوام متعددة الجيجابايت. أما ZGC و Shenandoah فتستهدفان فترات توقف أقل من جزء من الألف من الثانية على أكوام كبيرة جدًا، وهما خياران جيدان للخدمات الحساسة للتأخير التي تعمل على Java 17 أو الأحدث.

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

نعم. تقوم أدوات الضبط المدعومة بالذكاء الاصطناعي بتحليل سجلات جمع البيانات المهملة، ومعدلات التخصيص، ومخططات التوقف المؤقت للتوصية بأحجام الذاكرة المخصصة، وعلامات جامع البيانات المهملة، ونسب الجيل الصغير. وهي تُقصر حلقة التغذية الراجعة مقارنةً بالضبط اليدوي، خاصةً في أحمال العمل من نوع G1 وZGC وShenandoah.

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

تلخيص هذه التدوينة بـ: