في Java ، تتضمن إدارة الذاكرة الخاصة بها جانبين: تخصيص الذاكرة (عند إنشاء كائنات Java) وإعادة تدوير الذاكرة. يتم إكمال كلا الجانبين من العمل تلقائيًا بواسطة JVM ، مما يقلل من صعوبة التعلم لمبرمجي Java وتجنب خطر تشغيل الذاكرة مباشرة مثل C/C ++. ومع ذلك ، فهذا على وجه التحديد لأن إدارة الذاكرة تتم معالجتها بالكامل من قبل JVM أن العديد من مبرمجي Java لم يعد يهتمون بتخصيص الذاكرة ، مما يؤدي إلى عدم كفاءة العديد من البرامج وتستهلك الذاكرة. لذلك ، يجب على مبرمجي Java فهم JVM في النهاية من أجل كتابة برامج أكثر كفاءة واستفادة كاملة من الذاكرة المحدودة.
1. حالة جافا في الذاكرة
أولاً ، دعنا نكتب رمزًا كمثال:
شخص
اختبار الحزمة ؛ استيراد java.io.serializable ؛ شخص الطبقة العامة ينفذ قابلة للتسلسل {static final long serialversionuid = 1L ؛ اسم السلسلة // اسم صديق // Friends Public Person () {} public (اسم السلسلة) {super () ؛ this.name = name ؛ }} test.java
اختبار الحزمة ؛ اختبار الفئة العامة {public static void main (string [] args) {person p1 = new شخص ("kevin") ؛ الشخص p2 = شخص جديد ("المطر") ؛ الشخص p3 = شخص جديد ("مشمس") ؛ p1.friend = p2 ؛ p3 = p2 ؛ p2 = فارغة ؛ }} إذا قمت برسم مرجع الكائن في الجانب الرئيسي في test.java أعلاه إلى رسم تخطيطي مرجعي للكائن بدءًا من الطريقة الرئيسية ، فهذا مثل هذه (القمم هي الكائنات والمراجع ، والحواف الموجه هي علاقات مرجعية):
عند تشغيل البرنامج ، بعد اعتباره رسم بياني موجه ، يمكن تقسيمه إلى ثلاثة أنواع:
1) حالة قابلة للتحقيق: بعد إنشاء كائن ، يشير أكثر من متغير مرجعي. في رسم بياني موجه ، يمكنك الانتقال إلى الكائن من قمة البداية ، وهو في حالة يمكن الوصول إليها.
2) الحالة القابلة للاسترداد: إذا لم يعد كائن في البرنامج لديه أي متغيرات مرجعية تشير إليها ، فسيقوم أولاً بإدخال الحالة القابلة للاستعادة ، وفي هذا الوقت ، لا يمكن أن ينتقل إلى الكائن من قمة البداية للرسم البياني الموجه. في هذه الحالة ، تكون آلية جمع القمامة في النظام جاهزة لإعادة تدوير الذاكرة التي يشغلها الكائن. قبل إعادة التدوير ، سيقوم النظام باستدعاء طريقة اللمسات الأخيرة () لتنظيف المورد. إذا تم استرداد أكثر من متغير مرجعي بعد فرز المورد ، فسيصبح الكائن حالة يمكن الوصول إليها مرة أخرى ؛ وإلا فإنه سوف يدخل حالة لا يمكن الوصول إليها.
3) الحالة التي لا يمكن الوصول إليها: عندما يتم قطع جميع ارتباطات الكائن ويقوم النظام باستدعاء طريقة النهائي () لتنظيف المورد لا يزال لا يجعل الكائن قابلاً للوصول إليه ، فإن الكائن سيفقد مرجعًا بشكل دائم ويصبح حالة لا يمكن الوصول إليها ، وسيقوم النظام بإعادة تدوير الموارد التي يحتلها الكائن حقًا.
مخطط الانتقال للحالات الثلاث المذكورة أعلاه هو كما يلي:
2. 4 إشارات إلى كائنات من جافا
1) مرجع قوي: قم بإنشاء كائن وقم بتعيين هذا الكائن مباشرةً إلى متغير ، على سبيل المثال: شخص شخص = شخص جديد ("مشمس") ؛ بغض النظر عن مدى ضيقة موارد النظام ، لن يتم إعادة تدوير الكائن القوي المرجعية أبدًا ، حتى لو لم يتم استخدامه مرة أخرى في المستقبل.
2) المرجع الناعم: تم تنفيذها من خلال فئة softreference ، على سبيل المثال: softreference <Person> p = new softreference <Phone> (شخص جديد ("المطر"))
3) المرجع الضعيف: تم تنفيذها من خلال فئة الضعف ، على سبيل المثال: ProfErference <Person> p = New Preferference <Person> (شخص جديد ("المطر")) ؛ بغض النظر عما إذا كانت الذاكرة كافية ، سيتم إعادة تدوير النظام بالتأكيد أثناء جمع القمامة.
4) اقتباس افتراضي: لا يمكن استخدامه بمفرده ، ويستخدم بشكل أساسي لتتبع حالة الكائن الذي يتم جمعه القمامة. تم تنفيذ
اختبار الحزمة ؛ استيراد java.lang.ref.phantomReference ؛ استيراد java.lang.ref.referencequeue ؛ اختبار الفئة العامة {public static void main (string [] args) {// إنشاء شخص كائن الشخص = شخص جديد ("مشمس") ؛ // إنشاء قائمة انتظار مرجعية مرجعية <Person> rq = new ReferenceQueue <Person> () ؛ // قم بإنشاء مرجع افتراضي ، دع هذا المرجع الافتراضي المرجعية إلى كائن الشخص phantomreference <Person> pr = new phantomreference <Phone> (الشخص ، RQ) ؛ // تسوية المتغيرات المرجعية وكائنات الشخص المراجع الشخص = فارغ ؛ // حاول الحصول على الكائن المشار إليه بواسطة المرجع الظاهري // وجدت أن البرنامج لا يمكنه الوصول إلى الكائن المشار إليه من خلال المرجع الظاهري ، وبالتالي فإن الإخراج هنا هو system.out.println (pr.get ()) ؛ // قسامة مجموعة القمامة system.gc () ؛ system.runfinization () ؛ // لأنه بمجرد إعادة تدوير الكائن الموجود في المرجع الظاهري ، سيتم إدخال المرجع الافتراضي في قائمة الانتظار المرجعية // لذا استخدم المرجع لأول مرة في قائمة الانتظار في قائمة الانتظار للمقارنة مع PR ، وإخراج STYSE.out.println (rq.poll () == PR) ؛ }}نتائج التشغيل:
3. آلية جمع القمامة جافا
في الواقع ، تقوم مجموعة Java Garbage بشكل أساسي بأمرين: 1) إعادة تدوير الذاكرة 2)
3.1 خوارزمية جمع القمامة
1) إعادة التدوير التسلسلي (وحدة المعالجة المركزية واحدة فقط) وإعادة التدوير المتوازي (وحدات المعالجة المركزية المتعددة مفيدة): إعادة التدوير التسلسلي تعني أنه بغض النظر عن عدد وحدات المعالجة المركزية التي لدى النظام ، فإنه دائمًا ما يكون وحدة المعالجة المركزية واحدة فقط لأداء عمليات جمع القمامة. تعني إعادة التدوير المتوازي تقسيم أعمال إعادة التدوير بأكملها إلى أجزاء متعددة ، حيث يتم مسؤولية كل جزء من وحدة المعالجة المركزية ، بحيث يمكن إعادة تدوير وحدة المعالجة المركزية المتعددة بالتوازي. إعادة التدوير الموازية فعالة للغاية في التنفيذ ، لكنها تزيد من التعقيد ، وهناك أيضًا بعض الآثار الجانبية ، مثل الزيادة العشوائية في الذاكرة.
2) التنفيذ المتزامن وإيقاف التطبيق: كما يوحي الاسم ، فإن طريقة جمع القمامة الخاصة بها ستتسبب في تعليق التطبيق أثناء إجراء جمع القمامة. على الرغم من أن جمع القمامة من التنفيذ المتزامن لن يتسبب في توقف التطبيق ، نظرًا لأن التنفيذ المتزامن يحتاج القمامة إلى حل النزاعات مع التطبيق (يجوز للتطبيق تعديل الكائنات أثناء عملية جمع القمامة) ، فإن نظام النظام العلوي للتنفيذ المتزامن لجمع القمامة أعلى من التوقف عن العالم ، ويتطلب المزيد من الذاكرة عند التنفيذ.
3) ضغط وغير ضغط ونسخة:
① يقوم جامع القمامة الذي يدعم الانضغاط (ضغط العلامات = الضغط + ضغط +) بنقل جميع الكائنات القابلة للوصول معًا ، ثم إعادة تدوير جميع الذاكرة المحتلة مسبقًا ، مما يقلل من تجزئة الذاكرة.
② يحتاج جامع القمامة غير المضغوط (Mark-Clear) إلى اجتيازه مرتين. في المرة الأولى التي تصل فيها أولاً إلى جميع الكائنات القابلة للوصول وتمييزها على أنها حالات يمكن الوصول إليها. في المرة الثانية التي تسهل فيها منطقة الذاكرة بأكملها وكائنات إعادة تدويرها التي لا يتم وضع علامة على حالات يمكن الوصول إليها. طريقة إعادة التدوير هذه ليست مضغوطة ولا تتطلب ذاكرة إضافية ، ولكنها ستنتج تجزئة إذا استغرق الأمر اثنين.
③ Copy Copy Garbage Collector: قسّم ذاكرة الكومة إلى مساحين متطابقين ، يمكنك الوصول إلى كل كائن يمكن الوصول إليه من الجذر (على غرار قمة البداية للرسم البياني السابق الموجه) ، ونسخ جميع الكائنات التي يمكن الوصول إليها في الفضاء A إلى الفضاء B ، ثم إعادة تدوير مساحة A في وقت واحد. بالنسبة لهذه الخوارزمية ، نظرًا لأنك تحتاج فقط إلى الوصول إلى جميع الكائنات القابلة للوصول إليها ، ونسخ جميع الكائنات التي يمكن الوصول إليها بعيدًا ، وإعادة تدوير المساحة بأكملها مباشرةً ، وتجاهل الكائنات التي لا يمكن الوصول إليها على الإطلاق ، فإن تكلفة اجتياز المساحة صغيرة ، ولكنها تتطلب تكاليف نسخ ضخمة ومزيد من الذاكرة.
3.2 إعادة تدوير الأجيال لذاكرة الكومة
1) أساس إعادة تدوير الأجيال:
① طول وقت البقاء على قيد الحياة للكائن: يتم إعادة تدوير معظم الكائنات خلال الفترة الشابة - الأجيال المختلفة تتبنى استراتيجيات مختلفة لإعادة تدوير القمامة: نادراً
2) توليد ذاكرة الكومة:
① الجيل الشاب:
ⅰ آلية التدوير: لأن عدد الكائنات صغير ، يتم استخدام النسخ المتماثل وإعادة التدوير.
ⅱ منطقة التوحيد: تتكون من منطقة عدن واحدة ومناطق ناجية. منطقتان من الناجين في نفس الوقت ، يتم استخدام أحدهما لحفظ الكائن والآخر فارغ ؛ في كل مرة يتم فيها تنفيذ مجموعة Generation Garbage ، يتم نسخ الكائنات التي يمكن الوصول إليها في عدن ومن إلى المنطقة إلى المنطقة ، ويتم نسخ بعض الأجل منذ فترة طويلة إلى الشيخوخة ، ثم يتم مسح العدن ومن الفضاء ، وأخيراً يصبح الأصل إلى الفضاء من الفضاء ، ويصبح الأصل من الفضاء إلى الفضاء.
ⅲ مصدر الكائن: يتم تعيين معظم الكائنات إلى منطقة عدن أولاً ، وسيتم تعيين بعض الكائنات الكبيرة مباشرة إلى الجيل القديم.
ⅳ تردد إعادة التدوير: نظرًا لأن معظم كائنات الجيل الشباب تدخل بسرعة حالة لا يمكن الوصول إليها ، فإن تردد إعادة التدوير مرتفع وسرعة إعادة التدوير سريعة.
جيل مولود:
ⅰ آلية التدوير: استخدم خوارزمية ضغط العلامة للتعافي.
ⅱ مصدر الكائنات: 1. الكائن الكبير يدخل مباشرة إلى الشيخوخة.
2. إعادة تدوير تكرار الكائنات القابلة للوصول مع وقت بقاء طويل في الجيل الشاب: نظرًا لأن عدد قليل من الأشياء تموت ، فإن تردد التنفيذ ليس مرتفعًا ويستغرق إكماله وقتًا طويلاً.
جيل جيل:
ⅰ الغرض: يستخدم لتحميل الفئة والطريقة والمعلومات الأخرى. الافتراضي هو 64 متر ولن يتم إعادة تدويره. ⅱ Object المصدر: على سبيل المثال: بالنسبة للأطر مثل السبات والربيع ، فإن فئات التوليد الديناميكية AOP غالبًا ما تولد عددًا كبيرًا من فئات الوكيل الديناميكية ، لذلك هناك حاجة إلى مزيد من ذاكرة الجيل الدائم. لذلك غالبًا ما نواجه java.lang.outofmemoryerror: خطأ في الفضاء permgen عند تصحيح السبات. هذا هو الخطأ الناجم عن استنفاد ذاكرة الجيل الدائم.
ⅲ تردد إعادة التدوير: لن يتم إعادة تدويره
3.3 جامعي القمامة المشتركة
1) إعادة التسلسل التسلسلي (يتم استخدام وحدة المعالجة المركزية واحدة فقط): يستخدم الجيل الشاب خوارزمية النسخ التسلسلية ؛ يستخدم الجيل القديم خوارزمية ضغط العلامة التسلسلية (ثلاث مراحل: Mark Mark - Clear Sweep - Compress Compact) ، سيتم إيقاف البرنامج خلال فترة إعادة التدوير.
2) إعادة التدوير الموازي: الخوارزمية المستخدمة في الجيل الشاب هي نفس المعادلة التسلسلية ، لكنها تضيف فقط معالجة متوازية متعددة CPU ؛ إن معالجة الجيل القديم هي بالضبط نفس معالجة التسلسل التسلسلي ، ولا تزال موضوعًا واحدًا.
3) جامع الضغط المتوازي: إن معالجة الجيل الشاب هي بالضبط نفس الخوارزمية مثل جامع متوازي ؛ ولكن يتم استخدام خوارزميات مختلفة للجيل القديم ، والتي تنقسم فعليًا إلى مناطق مختلفة ثم خوارزمية وضع العلامات والضغط:
① تقسيم القديم إلى عدة مناطق ثابتة ؛
② مرحلة علامة (موازية متعددة الخيوط) ، وضع علامة على الأشياء التي يمكن الوصول إليها ؛
③ مرحلة الملخص (التنفيذ التسلسلي). عندما تجد منطقة تصل إلى القيمة العددية (كثافة الكائن المنخفضة) من اليسار ، يتم ضغط هذه المنطقة ومنطقةها اليمنى واستردادها. الطرف الأيسر هي المساحة الكثيفة ④ مرحلة مضغوطة (موازية متعددة الخيوط) ، وتحديد المناطق التي تحتاج إلى تحميل ، ونسخ البيانات إلى هذه المناطق بالتوازي. بعد هذه العملية ، هناك عدد كبير من الكائنات النشطة في أحد طرفي الجيل القديم ، ومساحة كبيرة من الطرف الآخر.
4) تحديد التزامن - التنظيف وإعادة التدوير (CMS): إن معالجة الجيل الشاب هي بالضبط نفس الخوارزمية التي يتمتع بها متوازيون متوازيين ؛ ولكن يتم استخدام خوارزميات مختلفة للجيل القديم ، ولكن لا تزال خوارزمية تنظيف العلامات تستخدم:
① التعريف الأولي (توقف البرنامج): يمثل الكائن المشار إليه مباشرة (كائن المستوى الأول) ؛
② التعريف المتزامن (تشغيل البرنامج): ابحث عن كائنات أخرى قابلة للوصول من خلال الكائنات من المستوى الأول ؛
③ re-mark (وقفة البرنامج): كائنات إعادة تدوير متوازية متعددة الخيوط والتي قد تكون قد تفوت بسبب التزامن (مجرد التحدث ، فهو مضاد للتفتيت)
④ التنظيف المتزامن (تشغيل البرنامج)
4. نصائح إدارة الذاكرة
1) حاول استخدام الكمية المباشرة ، على سبيل المثال: String Javastr = "عملية نمو التدريب المهني للمدارس الابتدائية" ؛
2) استخدم StringBuilder و StringBuffer لتنفيذ سلسلة متسلسلة وغيرها من العمليات ؛
3) إطلاق كائنات عديمة الفائدة في أقرب وقت ممكن ؛
4) حاول استخدام المتغيرات الثابتة بأقل قدر ممكن ؛
5) ذاكرة التخزين المؤقت بشكل شائع الكائنات: يمكن تنفيذها باستخدام ذاكرة التخزين المؤقت مفتوحة المصدر مفتوح المصدر ، على سبيل المثال: Oscache ، ehcache ؛
6) حاول عدم استخدام طريقة اللمسات الأخيرة () ؛
7) يمكنك التفكير في استخدام Soft Reference Softreference عند الضرورة.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.