فهم نموذج ذاكرة JVM، إدارة الذاكرة في جافا مهمة جدًا إذا كنت ترغب في فهم عمل جمع القمامة في جافا. اليوم سنلقي نظرة على إدارة الذاكرة في جافا، وأجزاء مختلفة من ذاكرة JVM، وكيفية مراقبتها وضبط جمع القمامة.
نموذج ذاكرة جافا (JVM)
كما يمكنك أن ترى في الصورة أعلاه، تنقسم ذاكرة JVM إلى أجزاء منفصلة. على المستوى العام، تُقسم ذاكرة الذاكرة (Heap memory) لـ JVM إلى جزئين بدنيًا – الجيل الشاب (Young Generation) والجيل القديم (Old Generation).
إدارة الذاكرة في جافا – الجيل الشاب (Young Generation)
الجيل الشاب هو المكان الذي يتم فيه إنشاء جميع الكائنات الجديدة. عندما يمتلئ الجيل الشاب، يتم أداء جمع القمامة. يُسمى هذا الجمع بالقمامة بالقديمة (Minor GC). الجيل الشاب مقسم إلى ثلاثة أجزاء – ذاكرة إيدن (Eden Memory) واثنين من مساحات ذاكرة البقاء (Survivor Memory). النقاط المهمة حول مساحات الجيل الشاب:
- معظم الكائنات الجديدة التي يتم إنشاؤها تقع في مساحة الذاكرة Eden.
- عندما يتم ملء مساحة Eden بالكائنات، يتم إجراء Minor GC وتتم نقل جميع الكائنات الناجية إلى إحدى مساحات الناجيين.
- يتحقق Minor GC أيضًا من الكائنات الناجية وينقلها إلى المساحة الناجية الأخرى. لذا في أي وقت، يكون إحدى مساحات الناجيين دائمًا فارغة.
- يتم نقل الكائنات التي نجت بعد العديد من دورات GC إلى مساحة الذاكرة العمرية القديمة. عادةً ما يتم ذلك عن طريق تحديد عتبة لعمر الكائنات الشبابية قبل أن يصبحوا مؤهلين للترقية إلى الجيل القديم.
إدارة الذاكرة في Java – الجيل القديم
يحتوي الجيل القديم للذاكرة على الكائنات التي يمتلكها الفترة الطويلة ونجت بعد العديد من جولات Minor GC. عادةً ما يتم إجراء جمعية غير ربحية في الجيل القديم للذاكرة عندما تكون كبيرة. يطلق على جمعية غير ربحية الجيل القديم Major GC وعادةً ما يستغرق وقتًا أطول.
حدث إيقاف العالم
جميع عمليات جمع القمامة هي حوادث “توقف العالم” لأن جميع خيوط التطبيق متوقفة حتى يكتمل العملية. نظرًا لأن الجيل الصغير يحتوي على الكائنات ذات المدى الحياة القصير، يكون جمع القمامة الطفيف سريعًا جدًا ولا يؤثر على التطبيق. ومع ذلك، يستغرق جمع القمامة الرئيسي وقتًا طويلاً لأنه يتحقق من جميع الكائنات الحية. يجب تقليل جمع القمامة الرئيسي لأن ذلك سيجعل التطبيق غير مستجيب أثناء فترة جمع القمامة. لذا، إذا كان لديك تطبيق مستجيب وحدثت الكثير من عمليات جمع القمامة الرئيسية، فستلاحظ أخطاء في الوقت المنقضي. يعتمد الوقت الذي يستغرقه جامع القمامة على الاستراتيجية المستخدمة لجمع القمامة. لهذا السبب، من الضروري مراقبة وضبط جامع القمامة لتجنب حدوث أخطاء في الوقت المنقضي في التطبيقات ذات الاستجابة العالية.
نموذج ذاكرة جافا – الجيل الدائم
الجيل الدائم أو “Perm Gen” يحتوي على بيانات التطبيق الضرورية التي تحتاجها JVM لوصف الفئات والأساليب المستخدمة في التطبيق. لاحظ أن Perm Gen ليست جزءًا من ذاكرة Java Heap. يتم ملء Perm Gen بواسطة JVM أثناء التشغيل بناءً على الفئات المستخدمة في التطبيق. تحتوي Perm Gen أيضًا على فئات وأساليب مكتبة Java SE. تتم جمع كائنات Perm Gen في جمع القمامة الكامل.
نموذج ذاكرة جافا – منطقة الطريقة
منطقة الطريقة هي جزء من الفضاء في Perm Gen وتُستخدم لتخزين هيكل الصف (الثوابت أثناء التشغيل والمتغيرات الثابتة) والشفرة للطرق والبناة.
نموذج ذاكرة جافا – مجموعة الذاكرة
تتم إنشاء مجموعات الذاكرة من قبل مديري ذاكرة JVM لإنشاء مجموعة من الكائنات غير القابلة للتغيير إذا كانت التنفيذ يدعم ذلك. سلسلة النص هي مثال جيد على هذا النوع من مجموعة الذاكرة. يمكن أن تنتمي مجموعة الذاكرة إلى Heap أو Perm Gen، اعتمادًا على تنفيذ مدير ذاكرة JVM.
نموذج ذاكرة جافا – مجموعة الثوابت أثناء التشغيل
مجموعة الثوابت أثناء التشغيل هي التمثيل الزمني للصف من فئة معينة في وقت التشغيل لمجموعة الثوابت. تحتوي على الثوابت الزمنية للفئة والطرق الثابتة. مجموعة الثوابت أثناء التشغيل هي جزء من منطقة الطريقة.
نموذج ذاكرة جافا – ذاكرة الكومة في جافا
تُستخدم ذاكرة الكومة في جافا لتنفيذ خيط معين. تحتوي على قيم محددة للطريقة ذات مدى قصير ومراجع إلى كائنات أخرى في الكومة التي يتم الإشارة إليها من الطريقة. يجب عليك قراءة الفرق بين ذاكرة الكومة والذاكرة العشوائية.
إدارة الذاكرة في جافا – تبديلات ذاكرة الكومة في جافا
توفر جافا العديد من تبديلات الذاكرة التي يمكننا استخدامها لتعيين أحجام الذاكرة ونسبها. بعض تبديلات الذاكرة المستخدمة بشكل شائع هي:
VM Switch | VM Switch Description |
---|---|
-Xms | For setting the initial heap size when JVM starts |
-Xmx | For setting the maximum heap size. |
-Xmn | For setting the size of the Young Generation, rest of the space goes for Old Generation. |
-XX:PermGen | For setting the initial size of the Permanent Generation memory |
-XX:MaxPermGen | For setting the maximum size of Perm Gen |
-XX:SurvivorRatio | For providing ratio of Eden space and Survivor Space, for example if Young Generation size is 10m and VM switch is -XX:SurvivorRatio=2 then 5m will be reserved for Eden Space and 2.5m each for both the Survivor spaces. The default value is 8. |
-XX:NewRatio | For providing ratio of old/new generation sizes. The default value is 2. |
في معظم الأحيان، تكون الخيارات المذكورة أعلاه كافية، ولكن إذا كنت ترغب في التحقق من خيارات أخرى أيضًا، يرجى التحقق من صفحة الخيارات الرسمية لآلة الجافا الظاهرية (JVM).
إدارة الذاكرة في جافا – تجميع القمامة في جافا
جمع القمامة في جافا هو العملية التي تهدف إلى تحديد وإزالة الكائنات غير المستخدمة من الذاكرة وتحرير المساحة لتخصيصها للكائنات التي سيتم إنشاؤها في معالجة المستقبل. واحدة من أفضل ميزات لغة برمجة جافا هي تجميع القمامة التلقائي، على عكس لغات البرمجة الأخرى مثل السي التي تتطلب عمليات تخصيص وإلغاء تخصيص الذاكرة بشكل يدوي. جمّاع القمامة هو البرنامج الذي يعمل في الخلفية والذي يفحص جميع الكائنات في الذاكرة ويحدد الكائنات التي لا تُشير إليها أي جزء من البرنامج. يتم حذف كل هذه الكائنات غير المشار إليها ويتم استعادة المساحة لتخصيصها للكائنات الأخرى. إحدى الطرق الأساسية لتجميع القمامة تشمل ثلاث خطوات:
- التحديد: هذه هي الخطوة الأولى حيث يحدد جمّاع القمامة أي الكائنات قيد الاستخدام وأي الكائنات ليست قيد الاستخدام.
- الحذف العادي: يقوم جمّاع القمامة بإزالة الكائنات غير المستخدمة واستعادة المساحة الفارغة لتخصيصها للكائنات الأخرى.
- الحذف مع التجميع: لتحسين الأداء، بعد حذف الكائنات غير المستخدمة، يمكن نقل جميع الكائنات الباقية لتكون معًا. سيؤدي ذلك إلى زيادة أداء تخصيص الذاكرة للكائنات الجديدة.
هناك مشكلتان مع النهج البسيط للتحديد والحذف.
- أولاً ، ليس فعّالًا لأن معظم الكائنات الجديدة التي تم إنشاؤها ستصبح غير مستخدمة
- ثانياً، الكائنات التي تُستخدم لعدة دورات جمع القمامة من المحتمل أن تظل مستخدمة في دورات مستقبلية أيضًا.
النقائص المذكورة أعلاه في النهج البسيط هي السبب في أن جمع القمامة في جافا هو تصنيفي ولدينا جيل شاب وجيل قديم في ذاكرة الأسطوانة. لقد شرحت بالفعل أعلاه كيف يتم فحص الكائنات ونقلها من مساحة تصنيفية إلى أخرى بناءً على Minor GC و Major GC.
إدارة الذاكرة في جافا – أنواع جمع القمامة في جافا
هناك خمسة أنواع من أنواع جمع القمامة التي يمكننا استخدامها في تطبيقاتنا. نحتاج فقط إلى استخدام مفتاح JVM لتمكين استراتيجية جمع القمامة للتطبيق. دعونا نلقي نظرة على كل منها واحدة تلو الأخرى.
- GC السلسلي (-XX:+UseSerialGC): يستخدم GC السلسلي النهج البسيط علامة ، استبدال ، ضغط لجمع القمامة في الأجيال الشابة والقديمة أي Minor و Major GC. GC السلسلي مفيد في الآلات العميلية مثل تطبيقاتنا المستقلة البسيطة والآلات ذات المعالجات الأصغر. إنه جيد للتطبيقات الصغيرة ذات أثر ذاكرة منخفض.
- جمع التجميع المتوازي (-XX:+UseParallelGC): التجميع المتوازي مشابه للتجميع التسلسلي باستثناء أنه ينشئ N خيوط لتجميع النفايات في الجيل الشاب حيث يكون N عدد أنوية وحدة المعالجة المركزية في النظام. يمكننا التحكم في عدد الخيوط باستخدام الخيار
-XX:ParallelGCThreads=n
في الآلة الظاهرية لجافا. يُطلق على جامع النفايات المتوازي أيضًا جامع الإنتاجية لأنه يستخدم وحدات معالجة متعددة لتسريع أداء التجميع. يستخدم جمع التجميع المتوازي خيطًا واحدًا لتجميع النفايات في الجيل القديم. - تجميع الجيل القديم المتوازي (-XX:+UseParallelOldGC): هذا مشابه لتجميع التجميع المتوازي باستثناء استخدام عدة خيوط لكل من جيل الشباب وجيل النفايات القديمة.
- جامع الترصيع التفاعلي (CMS) (-XX:+UseConcMarkSweepGC): يشار إلى جامع CMS أيضًا بجامع تقليل الانقطاعات المتزامن. يقوم بتنظيف النفايات لجيل النفايات القديم. يحاول جامع CMS تقليل الانقطاعات بسبب جمع النفايات عن طريق القيام بمعظم عمل تنظيف النفايات بشكل متزامن مع خيوط التطبيق. يستخدم جامع CMS نفس خوارزمية جامع الجيل الشاب المتوازي. يعتبر هذا جامع النفايات مناسبًا لتطبيقات الاستجابة حيث لا يمكننا تحمل أوقات انقطاع طويلة. يمكننا تحديد عدد الخيوط في جامع CMS باستخدام الخيار
-XX:ParallelCMSThreads=n
في الآلة الظاهرية لجافا. - جمّاع النفايات G1 (-XX:+UseG1GC): جمّاع النفايات الأول أو جي وان هو متوفر من جافا 7 وهدفه الطويل المدى هو استبدال جمّاع النفايات CMS. يعتبر جمّاع G1 جمّاعًا متوازيًا ومتزامنًا ويضغط بشكل تدريجي بين الفاصلة للحد من التوقفات. لا يعمل جمّاع النفايات الأول بنفس طريقة الجمّاعات الأخرى ولا يوجد مفهوم لمساحة الجيل الشاب والجيل القديم. يقسم مساحة الذاكرة العشوائية إلى عدة مناطق متساوية الحجم. عند استدعاء جمّاع النفايات، يقوم أولاً بجمع المنطقة التي تحتوي على بيانات معيشية أقل، وبالتالي “النفايات أولاً”. يمكن العثور على مزيد من التفاصيل حوله في مستندات Oracle لجمّاع النفايات الأول.
إدارة الذاكرة في جافا – مراقبة جمع النفايات في جافا
يمكننا استخدام سطر الأوامر في جافا بالإضافة إلى أدوات واجهة المستخدم لمراقبة أنشطة جمع القمامة لتطبيق ما. كمثال لي، أنا استخدم أحد تطبيقات الديمو المقدمة من تنزيلات جافا SE. إذا كنت ترغب في استخدام نفس التطبيق، اذهب إلى صفحة تنزيلات جافا SE وقم بتنزيل JDK 7 و JavaFX Demos and Samples. التطبيق العيني الذي أستخدمه هو Java2Demo.jar ويوجد في الدليل jdk1.7.0_55/demo/jfc/Java2D
. ومع ذلك، هذه خطوة اختيارية ويمكنك تشغيل أوامر مراقبة جمع القمامة لأي تطبيق جافا. الأمر الذي استخدمته لبدء التطبيق التوضيحي هو:
pankaj@Pankaj:~/Downloads/jdk1.7.0_55/demo/jfc/Java2D$ java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar Java2Demo.jar
jstat
يمكننا استخدام أداة سطر الأوامر jstat
لمراقبة ذاكرة JVM وأنشطة جمع القمامة. يأتي مع JDK القياسية، لذا لا داعي للقيام بأي شيء آخر للحصول عليه. لتنفيذ jstat
، تحتاج إلى معرف العملية للتطبيق، يمكنك الحصول عليه بسهولة باستخدام الأمر ps -eaf | grep java
.
pankaj@Pankaj:~$ ps -eaf | grep Java2Demo.jar
501 9582 11579 0 9:48PM ttys000 0:21.66 /usr/bin/java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseG1GC -jar Java2Demo.jar
501 14073 14045 0 9:48PM ttys002 0:00.00 grep Java2Demo.jar
لذلك، معرف العملية لتطبيقي جافا هو 9582. الآن يمكننا تشغيل الأمر jstat كما هو موضح أدناه.
pankaj@Pankaj:~$ jstat -gc 9582 1000
S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 0.0 8192.0 7933.3 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
1024.0 1024.0 0.0 0.0 8192.0 8026.5 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
1024.0 1024.0 0.0 0.0 8192.0 8030.0 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
1024.0 1024.0 0.0 0.0 8192.0 8122.2 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
1024.0 1024.0 0.0 0.0 8192.0 8171.2 42108.0 23401.3 20480.0 19990.9 157 0.274 40 1.381 1.654
1024.0 1024.0 48.7 0.0 8192.0 106.7 42108.0 23401.3 20480.0 19990.9 158 0.275 40 1.381 1.656
1024.0 1024.0 48.7 0.0 8192.0 145.8 42108.0 23401.3 20480.0 19990.9 158 0.275 40 1.381 1.656
الوسيطة الأخيرة لـ jstat هي فترة الوقت بين كل إخراج، لذا ستقوم بطباعة بيانات الذاكرة وجمع القمامة كل ثانية واحدة. دعونا نتعرف على كل عمود واحد تلو الآخر.
- S0C و S1C: يعرض هذا العمود حجم منطقتي الناجي 0 والناجي 1 الحالي بالكيلوبايت.
S0U و S1U : يعرض هذا العمود استخدام الناجي 0 والناجي 1 الحالي بالكيلوبايت. لاحظ أن إحدى مناطق الناجي فارغة طوال الوقت. - S0U و S1U: يظهر هذا العمود استخدام المنطقتين Survivor0 و Survivor1 حاليًا في KB. لاحظ أن إحدى مناطق النجاة فارغة دائمًا.
- EC و EU: تظهر هذه الأعمدة الحجم الحالي والاستخدام الحالي لفضاء Eden في KB. لاحظ أن حجم EU يزداد وبمجرد تجاوزه EC، يتم استدعاء GC الثانوي ويتم تقليل حجم EU.
- OC و OU: تظهر هذه الأعمدة الحجم الحالي والاستخدام الحالي للجيل العجز في KB.
- PC و PU: تظهر هذه الأعمدة الحجم الحالي والاستخدام الحالي لل Perm Gen في KB.
- YGC و YGCT: يعرض عمود YGC عدد حدث GC في الجيل الشاب. يعرض عمود YGCT الوقت المتجمع لعمليات GC للجيل الشاب. لاحظ أن كلاهما يزداد في نفس الصف الذي ينخفض فيه قيمة EU بسبب GC الثانوي.
- FGC و FGCT: يعرض عمود FGC عدد حدث Full GC. يعرض عمود FGCT الوقت المتجمع لعمليات Full GC. لاحظ أن وقت Full GC مرتفع للغاية بالمقارنة مع زمن GC الجيل الشاب.
- GCT: يعرض هذا العمود الوقت المتجمع الإجمالي لعمليات GC. لاحظ أنه مجموع قيم عمودي YGCT و FGCT.
ميزة jstat هي أنه يمكن تنفيذه على الخوادم البعيدة أيضًا حيث لا يكون لدينا GUI. لاحظ أن مجموع S0C و S1C و EC هو 10m كما تم تحديده من خلال خيار JVM -Xmn10m
.
Java VisualVM مع Visual GC
إذا كنت ترغب في رؤية عمليات الذاكرة وتنظيف القمامة في واجهة المستخدم الرسومية، يمكنك استخدام أداة jvisualvm
. Java VisualVM هي جزء أيضًا من JDK، لذا لا داعي لتنزيلها بشكل منفصل. ما عليك سوى تشغيل أمر jvisualvm
في الطرفية لتشغيل تطبيق Java VisualVM. بمجرد الانطلاق، ستحتاج إلى تثبيت إضافة Visual GC من Tools – Plugins option، كما هو موضح في الصورة أدناه. بعد تثبيت Visual GC، ما عليك سوى فتح التطبيق من العمود الجانبي الأيسر والانتقال إلى قسم Visual GC. ستحصل على صورة لذاكرة JVM وتفاصيل جمع القمامة كما هو موضح في الصورة أدناه.
ضبط جمع القمامة في Java
ضبط جمع القمامة في جافا يجب أن يكون الخيار الأخير الذي تستخدمه لزيادة إنتاجية تطبيقك وذلك فقط عندما ترى انخفاضًا في الأداء بسبب مدة طويلة لجمع القمامة مما يتسبب في انتهاء وقت التطبيق. إذا رأيت أخطاء java.lang.OutOfMemoryError: PermGen space
في السجلات، فجرّب مراقبة وزيادة مساحة ذاكرة Perm Gen باستخدام الخيارات -XX:PermGen و -XX:MaxPermGen لآلة الجافا. قد تجرب أيضًا استخدام -XX:+CMSClassUnloadingEnabled
وتحقق من كيفية أدائه مع جامع القمامة CMS. إذا رأيت الكثير من عمليات GC الكاملة، فعليك محاولة زيادة مساحة الذاكرة للجيل القديم. بشكل عام، يتطلب ضبط جمع القمامة الكثير من الجهد والوقت ولا يوجد قاعدة صارمة وسريعة لذلك. ستحتاج إلى تجربة خيارات مختلفة ومقارنتها للعثور على الأفضل المناسب لتطبيقك. هذا كل شيء بالنسبة لنموذج الذاكرة في جافا وإدارة الذاكرة في جافا وجمع القمامة، آمل أن يساعدك ذلك في فهم ذاكرة JVM وعملية جمع القمامة.
Source:
https://www.digitalocean.com/community/tutorials/java-jvm-memory-model-memory-management-in-java