هناك 4 أنواع من المراجع في Java: StrongReference، وSoftReference، وWeakReference، وPhantomReference (مرجع الشبح الأسطوري هاها)،
ترتبط هذه الأنواع الأربعة من المراجع ارتباطًا وثيقًا بـ GC، فلننظر إلى تعريفاتها وسيناريوهات استخدامها واحدًا تلو الآخر:
1. مرجع قوي
StrongReference هو التطبيق المرجعي الافتراضي لـ Java، وسيظل موجودًا في JVM لأطول فترة ممكنة، وعندما لا يشير أي كائن إليه، سيتم إعادة تدويره بعد تنفيذ GC.
كود جافا
انسخ رمز الكود كما يلي:
@امتحان
الفراغ العام strongReference () {
مرجع الكائن = كائن جديد ()؛
/**
* إنشاء مرجع قوي من خلال المهمة
*/
Object strongReference = مرجع؛
AssureSame(reference, strongReference);
مرجع = فارغ؛
System.gc();
/**
* لن تتم إعادة تدوير StrongReference بعد GC
*/
AssurerNotNull(strongReference);
}
2. مرجع ضعيف وWeakHashMap
WeakReference، كما يوحي الاسم، هو مرجع ضعيف. عندما لا يكون للكائن المشار إليه مرجع قوي في JVM، سيتم إعادة تدوير المرجع الضعيف تلقائيًا بعد GC.
انسخ رمز الكود كما يلي:
@امتحان
الفراغ العام ضعيفالمرجع () {
مرجع الكائن = كائن جديد ()؛
WeakReference<Object> WeakRerference = new WeakReference<Object>(referent);
AssureSame(referent, WeakRerference.get());
مرجع = فارغ؛
System.gc();
/**
* بمجرد عدم وجود مرجع قوي يشير إلى المرجع، سيتم إعادة تدوير المرجع الضعيف تلقائيًا بعد GC
*/
AssurerNull(weakRerference.get());
}
يستخدم WeakHashMap WeakReference كمفتاح بمجرد عدم وجود مرجع قوي للمفتاح، سيقوم WeakHashMap تلقائيًا بحذف الإدخال ذي الصلة بعد GC.
انسخ رمز الكود كما يلي:
@امتحان
الفراغ العام ضعيفHashMap () يلقي InterruptedException {
Map<Object, Object> WeakHashMap = new WeakHashMap<Object, Object>();
مفتاح الكائن = كائن جديد ()؛
قيمة الكائن = كائن جديد ()؛
WeakHashMap.put(key, value);
AssurerTrue(weakHashMap.containsValue(value));
مفتاح = فارغ؛
System.gc();
/**
* انتظر حتى تدخل الإدخالات غير الصالحة إلى قائمة الانتظار المرجعية حتى يمكن مسحها في المرة التالية التي يتم فيها استدعاء getTable
*/
Thread.sleep(1000);
/**
* بمجرد عدم وجود إشارة قوية إلى المفتاح، سيقوم WeakHashMap تلقائيًا بحذف الإدخال ذي الصلة بعد GC
*/
AssureFalse(weakHashMap.containsValue(value));
}
3. مرجع ناعم
يتمتع SoftReference بشكل أساسي بنفس خصائص WeakReference. والفرق الأكبر هو أن SoftReference سيحتفظ بالمرجع لأطول فترة ممكنة حتى نفاد ذاكرة JVM قبل إعادة تدويره (ضمان الجهاز الافتراضي). هذه الميزة تجعل SoftReference مناسبًا جدًا لتطبيقات التخزين المؤقت.
انسخ رمز الكود كما يلي:
@امتحان
public void softReference() {
مرجع الكائن = كائن جديد ()؛
SoftReference<Object> softRerference = new SoftReference<Object>(referent);
AssurerNotNull(softRerference.get());
مرجع = فارغ؛
System.gc();
/**
* لن تتم إعادة تدوير المراجع الإلكترونية إلا قبل jvm OutOfMemory، لذا فهي مناسبة جدًا لتطبيقات التخزين المؤقت
*/
AssurerNotNull(softRerference.get());
}
4. المرجع الوهمي
باعتباره بطل هذه المقالة، فإن Phantom Reference يختلف كثيرًا عن WeakReference وSoftReference، لأن أسلوب get() الخاص به دائمًا ما يُرجع قيمة فارغة، ومن هنا يأتي اسمه.
كود جافا
انسخ رمز الكود كما يلي:
@امتحان
الفراغ العام phantomReferenceAlwaysNull() {
مرجع الكائن = كائن جديد ()؛
PhantomReference<Object> phantomReference = new PhantomReference<Object>(referent, new ReferenceQueue<Object>());
/**
* دائمًا ما تُرجع طريقة الحصول على المرجع الوهمي قيمة فارغة
*/
AssureNull(phantomReference.get());
}
قد تتساءل، ما فائدة المرجع الذي يُرجع دائمًا قيمة فارغة؟ يرجى الانتباه إلى المعلمة الثانية ReferenceQueue عند إنشاء PhantomReference (في الواقع، يمكن أن يحتوي WeakReference & SoftReference أيضًا على هذه المعلمة).
الاستخدام الوحيد لـ PhantomReference هو التتبع عندما يتم وضع المرجع في قائمة الانتظار في ReferenceQueue.
5. قائمة انتظار الصلة
عندما يبدأ WeakReference في إرجاع قيمة فارغة، يكون الكائن الذي يشير إليه جاهزًا لإعادة التدوير. في هذا الوقت، يمكن إجراء بعض أعمال التنظيف المناسبة. قم بتمرير قائمة الانتظار المرجعية إلى مُنشئ المرجع سيتم تلقائيًا إدراج الكائن في ReferenceQueue. يستخدم WeakHashMap ReferenceQueue لمسح الإدخالات التي لم تعد مفاتيحها تحتوي على مراجع قوية.
كود جافا
انسخ رمز الكود كما يلي:
@امتحان
مرجع الفراغ العامQueue () يطرح InterruptedException {
مرجع الكائن = كائن جديد ()؛
ReferenceQueue<Object>referenceQueue = new ReferenceQueue<Object>();
WeakReference<Object> WeakReference = new WeakReference<Object>(referent, ReferenceQueue);
AssureFalse(weakReference.isEnqueued());
المرجع<? يمتد الكائن> polled = signalQueue.poll();
تأكيدNull(استطلاع);
مرجع = فارغ؛
System.gc();
AssurerTrue(weakReference.isEnqueued());
المرجع<? يمتد الكائن> تمت إزالته = مرجع Queue.remove();
AssureNotNull(removed);
}
6. المرجع الوهمي مقابل المرجع الضعيف
يتمتع PhantomReference بفائدتين: أولاً، يسمح لنا بمعرفة متى يتم حذف الكائن من الذاكرة بالضبط. يمكن استخدام هذه الميزة لبعض الاحتياجات الخاصة (مثل Distributed GC وXWork وgoogle-guice الذي يستخدم PhantomReference أيضًا في بعض أعمال التنظيف).
ثانيًا، يمكن تجنب بعض المشكلات الأساسية الناجمة عن الإنهاء، كما ذكرنا أعلاه، فإن الوظيفة الوحيدة لـ PhantomReference هي التتبع عندما يتم إدراج المرجع في قائمة الانتظار، ولكن لدى WeakReference أيضًا وظائف مقابلة.
يتعلق الأمر بطريقة الإنهاء للكائن، وسيتم استدعاء هذه الطريقة قبل تنفيذ gc. إذا قام الكائن بتحميل طريقة الإنهاء بشكل زائد وقام عن عمد بإنشاء مرجع قوي لنفسه داخل الطريقة، فسيؤدي ذلك إلى عدم قدرة هذه الجولة من GC. قد يتسبب هذا الكائن في حدوث أي GC. والنتيجة النهائية هي وجود الكثير من البيانات المهملة في JVM، لكن استخدام OutOfMemory يمكن أن يتجنب هذه المشكلة، لأنه يتم إعادة تدوير PhantomReference بعد تنفيذ طريقة الإنهاء، مما يعني أنه لا يوجد. ربما لم يعد متاحًا في الوقت الحالي، إذا حصلنا على المرجع الأصلي، فلن تحدث المشكلة المذكورة أعلاه بالطبع، وهذا مثال متطرف للغاية ولا يحدث بشكل عام.
7. المقارنة
المراجع الناعمة مقابل الضعيفة مقابل المراجع الوهمية | ||||
---|---|---|---|---|
يكتب | غاية | يستخدم | عندما GCed | فئة التنفيذ |
مرجع قوي | مرجع عادي يبقي الكائنات حية طالما تمت الإشارة إليها. | مرجع عادي. | يمكن استعادة أي كائن لم تتم الإشارة إليه. | تقصير |
مرجع لينة | يبقي الكائنات حية بشرط وجود ذاكرة كافية. | للحفاظ على الكائنات حية حتى بعد قيام العملاء بإزالة مراجعهم (ذاكرة التخزين المؤقت الحساسة للذاكرة)، في حالة بدء العملاء في طلبها مرة أخرى عن طريق المفتاح. | بعد تمريرة gc الأولى، قرر JVM أنه لا يزال بحاجة إلى استعادة مساحة أكبر. | java.lang.ref.SoftReference |
مرجع ضعيف | يبقي الكائنات حية فقط أثناء استخدامها (يمكن الوصول إليها) من قبل العملاء. | الحاويات التي تحذف الكائنات التي لم تعد قيد الاستخدام تلقائيًا. | بعد أن يحدد gc أن الكائن لا يمكن الوصول إليه إلا بشكل ضعيف | java.lang.ref.WeakReference java.util.WeakHashMap |
المرجع الوهمي | يتيح لك التنظيف بعد الانتهاء ولكن قبل استعادة المساحة (يستبدل أو يزيد من استخدام Finalize()) | معالجة تنظيف خاصة | بعد الانتهاء. | java.lang.ref.PhantomReference |
8. ملخص
لن تتضمن التطبيقات العامة البرمجة المرجعية، ولكن فهم هذه المعرفة سيكون مفيدًا في فهم مبدأ عمل GC وضبط الأداء، ويمكن استخدامها أيضًا عند تنفيذ بعض المرافق الأساسية مثل التخزين المؤقت.