1. النوع المرجعي (باستثناء مرجع قوي)
يمكن فهم أن الفئة الفرعية المباشرة للمرجع تتم معالجتها بواسطة JVM ، لذلك ليس لها أي تأثير في ورث النوع المرجعي مباشرة في الكود. يمكن أن يكون ورثًا فقط من فئة الفئة الفرعية. تشمل أنواع الفئات الفرعية المقابلة ما يلي. (تجاهل تلك التي لا تستخدم في جافا ، مثل Jnireference)
softreference
ضعف
FinalReference
الوهمية
تم ذكر النوع المرجعي أعلاه أيضًا في Javadoc المقابل. تم تصميم FinalReference خصيصًا لطريقة الانتهاء ، وهناك العديد من سيناريوهات التطبيق المحددة الأخرى. من بينها ، يتم استخدام Softreference في ذاكرة التخزين المؤقت ذات الصلة بالذاكرة ، ويستخدم الضعف في معظم السيناريوهات المتعلقة بإعادة التدوير. يتم استخدام الفانتومري في سيناريوهات رد الاتصال لإعادة تدوير كائنات التغليف (مثل اكتشاف تسرب الموارد).
يمكنك عرض معلومات الفئة الفرعية مباشرة لعدة أنواع في IDE لفهم السيناريوهات التي يتم استخدامها في معظم الأطر عن طريق وراثة الأنواع المقابلة ، حتى نتمكن من إجراء معالجة اختيار النوع بالفعل.
2. المنشئ المرجعي
يوفر اثنين من المُنشئين داخليًا ، أحدهما مع قائمة انتظار والآخر بدون قائمة انتظار. معنى قائمة الانتظار هو أنه يمكننا مراقبة قائمة الانتظار هذه خارجيًا. وهذا هو ، إذا كان كائن على وشك إعادة تدويره ، فسيتم وضع كائن المرجع المقابل في قائمة الانتظار هذه. عندما نحصل على المرجع ، يمكننا القيام ببعض المعاملات.
إذا لم تقم بذلك ، يمكنك فقط تدريب الكائن المرجعي بشكل مستمر ، والحكم على ما إذا كان GET Inside يعود لاغية (لا يمكن لكائن فانتومري القيام بذلك ، فإن الحصول على إرجاع دائمًا ، لذلك يحتوي فقط على مُنشئ مع قائمة انتظار). كلتا الطريقتين لها سيناريوهات الاستخدام المقابلة ، اعتمادًا على التطبيق الفعلي. على سبيل المثال ، في DephashMap ، اخترت الاستعلام عن بيانات قائمة الانتظار لتحديد ما إذا كان سيتم إعادة تدوير أي كائن. بالنسبة إلى threadlocalmap ، يتم استخدامه لتحديد ما إذا كان GET () لاغية للمعالجة.
المنشئ المقابل هو كما يلي:
مرجع (مرجع t) {هذا (المرجع ، فارغ) ؛} مرجع (مرجع t ، مرجع <؟ super t> queue) {this.referent = referent ؛ this.queue = (قائمة الانتظار == فارغ)؟ ReferenceQueue.Null: قائمة الانتظار ؛}يمكن فهم قائمة الانتظار الخالية هنا على أنها قائمة انتظار لا تتطلب أي معالجة للبيانات في قائمة الانتظار الخاصة بها. ولن تصل إلى أي بيانات بداخلها.
في الكائن أعلاه ، يمثل المرجع الكائن الذي يشير إليه ، أي الكائن الذي يجب أن نلفه عندما نبنيه. يعني التعريف القائل بأن الكائن على وشك إعادة تدويره أن هذا الكائن ليس له أي مرجع آخر باستثناء المرجع (ليس أنه لم يتم الرجوع إليه حقًا ، ولكن لا يمكن الوصول إلى إمكانية الوصول إلى GCRoot لتجنب مشكلة المرجع الدائري).
قائمة الانتظار هي قائمة الانتظار التي يتم إخطارها عند إعادة تدوير الكائن. عند إعادة تدوير الكائن ، سيتم وضع الكائن المرجعي بأكمله (وليس الكائن المعاد تدويره) في قائمة الانتظار ، ثم يمكن للبرامج الخارجية الحصول على البيانات المقابلة عن طريق مراقبة قائمة الانتظار هذه.
3. سلسلة مرجعية مرجعية ومرجعية
قائمة الانتظار هنا هي قائمة انتظار اسمية ، ولكن لا يوجد بنية تخزين فعلية في الداخل. يعتمد تخزينها على العلاقة بين العقد الداخلية. يمكن فهم أن قائمة الانتظار عبارة عن بنية مماثلة لقائمة مرتبطة ، والعقدة هنا هي في الواقع المرجع نفسه. يمكن فهم أن قائمة الانتظار عبارة عن حاوية لقائمة مرتبطة ، والتي تخزن فقط عقدة الرأس الحالية ، ويتم الحفاظ على العقد اللاحقة بواسطة كل عقدة مرجعية نفسها خلال التالي.
قيمة الحالة المرجعية
يحتوي كل كائن مرجعي على وصف للحالة المقابلة ، وهو يصف نفسه والكائن ملفوف حاليًا ، لراحة الاستعلام أو تحديد المواقع أو المعالجة.
1. نشط: الحالة النشطة ، أي أن الكائن المقابل هو حالة مرجعية قوية ولم يتم إعادة تدويرها. في هذه الحالة ، لن يتم وضع الكائن في قائمة الانتظار. في هذه الحالة ، التالي هو NULL ، والقائمة الانتظار هي قائمة الانتظار المشار إليها عند تعريفها.
2. معلق: الاستعداد لوضعه في قائمة الانتظار. في هذه الحالة ، سيتم قائمة الكائنات التي سيتم معالجتها في قائمة الانتظار واحدًا تلو الآخر في قائمة الانتظار. خلال هذه النافذة الزمنية ، تكون الكائنات المقابلة في الحالة المعلقة. بغض النظر عن المرجع ، إذا دخلت هذه الحالة ، فيمكنك التفكير في أنه في الحالة المقابلة ، فإن التالي هو نفسه (الذي تم تعيينه بواسطة JVM) ، والقائمة الانتظار هي الإشارة إلى عندما يتم تعريفها.
3. enqueued: الكائن المقابل يتم إعادة تدويره بالفعل ، وتم وضع الكائن المرجعي المقابل في قائمة الانتظار. الخيط الخارجي جاهز للاستعلام عن قائمة الانتظار للحصول على البيانات المقابلة. في هذه الحالة ، التالي هو الكائن التالي الذي يجب معالجته ، وقائمة الانتظار هي كائن التعريف الخاص.
4. غير نشط: أي أن هذا الكائن قد تم استرداده من قائمة الانتظار من الخارج وتم معالجته. هذا يعني أنه يمكن إعادة تدوير هذا الكائن المرجعي ، ويمكن أيضًا إعادة تدوير الكائن المغطى داخليًا (تعتمد عملية إعادة التدوير الفعلية على ما إذا كان الإجراء الواضح يسمى). يمكن فهم أنه يجب إعادة تدوير أولئك الذين يدخلون هذه الحالة.
لا يحتاج JVM إلى تحديد قيمة الحالة لتحديد الحالة التي تكون فيها المرجع المقابل. يحتاج فقط إلى حساب التالي وقائمة الانتظار لإصدار الأحكام.
4. المرجع#الرأس
احفظ دائمًا أحدث العقدة التي تتم معالجتها في قائمة الانتظار الحالية. يمكنك النظر في قائمة الانتظار كقائمة قائمة انتظار أخيرة. عندما تدخل عقدة جديدة ، يتم اعتماد المنطق التالي.
newe.next = head ؛ head = newe ؛
ثم ، عند الحصول عليها ، استخدم المنطق المقابل
tmp = head ؛ head = tmp.next ؛ return tmp ؛
خامسا المرجع#التالي
بمعنى ، صف العقدة التالية المخزنة بواسطة العقدة المرجعية التي على وشك معالجتها. لكن التالي لن يكون له معنى إلا عند وضعه في قائمة الانتظار. من أجل وصف قيمة الحالة المقابلة ، بعد وضعها في قائمة الانتظار ، لن يشير قائمة الانتظار إلى قائمة الانتظار. بدلاً من ذلك ، سوف يشير إلى enqueued خاص. لأنه تم وضعه في قائمة الانتظار ، لن يتم وضعه في قائمة الانتظار مرة أخرى.
6. المرجع#المرجع
أي وصف الكائن الفعلي المشار إليه بالمرجع الحالي ، والذي سيتم معالجته بعناية كما هو مذكور في التعليقات التوضيحية. هذا هو ، عندما يتم إعادة تدوير هذا الشيء ، وإذا تم إعادة تدويره ، فسيتم ضبطه مباشرة على الفارغ ، ويمكن أن تتعلم البرامج الخارجية من الكائن المرجعي نفسه (بدلاً من المرجع) أن سلوك إعادة التدوير يحدث.
7. مرجع#enqueue المعلقة مرجع enqueue
هذه العملية هي عملية الكائن المرجعي من Active-> المعلق-> Encored. هذه الطريقة هي معالجة الكائن الذي يتعامل مع الحالة المعلقة كدولة مسغوطة. العملية المقابلة هي المنطق السابق ، أي أن العقدة موصية ، والرمز المقابل كما يلي.
r.queue = enqueued ؛ r.next = (head == null)؟ r: الرأس ؛ الرأس = r ؛ queuelength ++ ؛ lock.notifyall () ؛
آخر nitify يعني إخطار البرنامج الخارجي الذي يحظر قائمة الانتظار الحالية من قبل. (أي أن الكائن المعلق لم يتم الحصول عليه من قبل)
8. المرجع#TryHandlePending
أي أنه يتعامل مع تغيير الكائن المرجعي من النشط إلى الحالة المعلقة. داخل الكائن المرجعي ، يوجد مجال ثابت ، وإعلانه المقابل هو كما يلي:
/* قائمة المراجع التي تنتظر أن تكون enqueed. يضيف جامع * إشارات إلى هذه القائمة ، بينما يقوم مؤشر ترابط المعالج المرجعي بإزالة *. هذه القائمة محمية بواسطة كائن القفل أعلاه. تستخدم قائمة * الحقل المكتشف لربط عناصره. */مرجع ثابت خاص <Object> معلق = فارغ ؛
يمكن أن يُفهم أن JVM سيضع الكائن المراد معالجته على هذا الحقل الثابت عند GC. في الوقت نفسه ، يمثل حقل آخر تم اكتشافه الكائن التالي للكائن المراد معالجته. أي أنه يمكن فهم أن الكائن الذي يجب معالجته هو أيضًا قائمة مرتبطة. إنه في قائمة الانتظار من خلال الاكتشاف. ما عليك سوى الاستمرار في الاعتبار ، ثم الحصول على الكائن التالي باستمرار من خلال الاكتشاف. نظرًا لأن كلا الموضوعين قد يصلون إلى هذا الكائن المعلق ، فمن الضروري استخدام معالجة القفل.
عملية المعالجة المقابلة هي كما يلي:
إذا (معلق! = فارغ) {r = معلق ؛ // "مثيل" قد يرمي OutofMemoryError أحيانًا // ، فهل هذا قبل عدم الربط "R" من سلسلة "المعلقة" ... C = R extryof cleaner؟ (منظف) ص: فارغ ؛ // unlint 'r' من سلسلة "معلقة" معلقة = r.discovered ؛ R.Discovered = null ؛} // enqueue كائن المعالجة ، أي أنه يدخل مرجع حالة enqued <؟ كائن سوبر> q = r.queue ؛ if (q! = referencequeue.null) q.enqueue (r) ؛9. المرجع#واضح
امسح الكائن الأصلي المشار إليه بواسطة الكائن المرجعي ، بحيث لم يعد الوصول إلى الكائن الأصلي من خلال طريقة GET (). من فكرة التصميم المقابلة ، نظرًا لأنها أدخلت كائن قائمة الانتظار ، فهذا يعني أن الكائن المقابل يحتاج إلى إعادة تدويره لأنه لا توجد حاجة للوصول إلى الكائن الأصلي مرة أخرى. لن يتم استدعاء هذه الطريقة بواسطة JVM ، ويقوم JVM بمسح المرجع المقابل مباشرة من خلال العمليات الميدانية ، وتنفيذها المحدد يتسق مع الطريقة الحالية.
دلالات واضحة هي أن لاغية الإشارة.
بعد دخول كائن DepReference إلى قائمة الانتظار ، يكون المرجع المقابل فارغًا.
كائن Softreference ، إذا لم يدخل الكائن قائمة الانتظار عندما تكون الذاكرة كافية ، فلن يكون المرجع المقابل فارغًا. إذا كانت هناك حاجة إلى معالجتها (لا توجد ذاكرة كافية أو سياسات أخرى) ، يتم تعيين المرجع المقابل على NULL ثم أدخل قائمة الانتظار.
كائن FinalReference ، لأنه يحتاج إلى استدعاء كائنه اللامع ، حتى لو تم إدخال مرجعه في قائمة انتظار ، فلن تكون مرجعها لاغية ، أي أنه لن يتم مسحه.
كائن الفانتومري ، لأن الحصول على نفسه ينفذ لإرجاع NULL ، ليس مفيدًا للغاية. لأنه لن يتم مسحه بغض النظر عما إذا كان enqueue أم لا.
10.
كما ذكر أعلاه ، ستقوم JVM بتعيين الكائن ليتم معالجته في الكائن المعلق ، لذلك يجب أن يكون هناك مؤشر ترابط لإجراء عمليات enqueue المستمرة. يشير هذا الموضوع إلى مؤشر ترابط المعالج ، وأولويته هي max_priority ، أي الأعلى. يتم إنشاء عملية بدء التشغيل المقابلة تهيئة ثابتة ، والتي يمكن فهمها كما هو الحال عند استخدام أي كائن أو فئة مرجعية ، سيتم إنشاء هذا الموضوع وبدء تشغيله. الرمز المقابل كما يلي:
ثابت {threadgroup tg = thread.currentThRead (). getThReadGroup () ؛ لـ (threadgroup tgn = tg ؛ tgn! = null ؛ tg = tgn ، tgn = tg.getParent ()) ؛ معالج الموضوع = جديد مرجعية (TG ، "معالج المرجع") ؛ / * إذا كانت هناك أولوية خاصة للنظام فقط أكبر من * max_priority ، فسيتم استخدامها هنا */ handler.setPriority (thread.max_priority) ؛ Handler.setdaemon (صواب) ؛ Handler.start () ؛}أولويته هي الأعلى ، والتي يمكن فهمها على أنها الحاجة إلى معالجة الكائنات المرجعية بشكل مستمر. عند طباعة مؤشر ترابط تشغيل من خلال JSTACK ، يشير معالج المرجع المقابل إلى مؤشر الترابط الذي تم تهيئته هنا ، كما هو موضح أدناه:
11. JVM ذات الصلة
في كل نقطة من نقاط المعالجة أعلاه ، ترتبط بعملية إعادة تدوير JVM. أي أنه من المعتقد أن عملية GC ستعمل بالتزامن مع المرجع المقابل. على سبيل المثال ، باستخدام CMS Collector ، تشارك العملية preclean في العملية بأكملها المذكورة أعلاه ، ومعالجة ملاحظات Softreference ، إلخ. في نفس الوقت ، يجب أيضًا أن تكون المعالجة المختلفة للكائن المرجعي مرتبطًا بالنوع المحدد. تستخدم معالجة JVM المقابلة رمز C ++ ، لذلك يجب فرزها بعناية.
12. ملخص
مثل كائن FinalReference ، فإن المرجع والمرجع بأكمله هما مجموعة من مجموعات المعالجة التي تعمل معًا. من أجل ضمان دلالات مرجعية مختلفة ، يتم تحقيق العملية المتعلقة بـ JVM GC أخيرًا لسيناريوهات مختلفة ومستويات مرجعية مختلفة.
بالإضافة إلى ذلك ، لأن استخدام مؤشرات الترابط المرجعية وفتح مباشرة لمراقبة قوائم الانتظار أمر مزعج ومعقد للغاية. يمكنك الرجوع إلى FinalizAblerEffectQueue التي تنفذها Google Guava وكائن Finalizablereference المقابل. يمكن تبسيط عملية المعالجة قليلاً. ما سبق هو المحتوى الكامل لهذه المقالة ، وآمل أن يجلب بعض المساعدة لتعلم أو عمل الجميع.