การอ้างอิงใน Java มี 4 ประเภท: StrongReference, SoftReference, WeakReference และ PhantomReference (การอ้างอิงผีในตำนาน 555)
การอ้างอิงทั้งสี่ประเภทนี้มีความเกี่ยวข้องอย่างใกล้ชิดกับ GC ให้เราดูคำจำกัดความและสถานการณ์การใช้งานทีละรายการ:
1. การอ้างอิงที่ชัดเจน
StrongReference เป็นการใช้งานอ้างอิงเริ่มต้นของ Java มันจะคงอยู่ใน JVM ได้นานที่สุด เมื่อไม่มีวัตถุใดชี้ไปที่มัน มันจะถูกรีไซเคิลหลังจากการดำเนินการ GC
รหัสจาวา
คัดลอกรหัสรหัส ดังต่อไปนี้:
@ทดสอบ
โมฆะสาธารณะ strongReference () {
การอ้างอิงวัตถุ = วัตถุใหม่ ();
-
* สร้าง StrongReference ผ่านการมอบหมาย
-
วัตถุ strongReference = อ้างอิง;
assertSame (อ้างอิง, การอ้างอิงที่แข็งแกร่ง);
อ้างอิง = null;
System.gc();
-
* StrongReference จะไม่ถูกรีไซเคิลหลังจาก GC
-
assertNotNull (การอ้างอิงที่แข็งแกร่ง);
-
2. การอ้างอิงที่อ่อนแอ & WeakHashMap
WeakReference ตามชื่อคือการอ้างอิงที่อ่อนแอ เมื่อวัตถุที่อ้างอิงไม่มีการอ้างอิงที่รัดกุมใน JVM อีกต่อไป การอ้างอิงที่อ่อนแอจะถูกรีไซเคิลโดยอัตโนมัติหลังจาก GC
คัดลอกรหัสรหัส ดังต่อไปนี้:
@ทดสอบ
โมฆะสาธารณะอ่อนแออ้างอิง () {
การอ้างอิงวัตถุ = วัตถุใหม่ ();
WeakReference<Object>อ่อนแอRerference = ใหม่ WeakReference<Object>(อ้างอิง);
assertSame(อ้างอิง,weakRerference.get());
อ้างอิง = null;
System.gc();
-
* เมื่อไม่มีการอ้างอิงที่ชัดเจนที่ชี้ไปยังการอ้างอิง การอ้างอิงที่อ่อนแอจะถูกรีไซเคิลโดยอัตโนมัติหลังจาก GC
-
assertNull(weakRerference.get());
-
WeakHashMap ใช้ WeakReference เป็นคีย์ เมื่อไม่มีการอ้างอิงที่ชัดเจนไปยังคีย์ WeakHashMap จะลบรายการที่เกี่ยวข้องโดยอัตโนมัติหลังจาก GC
คัดลอกรหัสรหัส ดังต่อไปนี้:
@ทดสอบ
โมฆะสาธารณะอ่อนแอHashMap () พ่น InterruptedException {
แผนที่ <Object, Object>อ่อนแอHashMap = ใหม่ WeakHashMap<Object, Object>();
รหัสวัตถุ = วัตถุใหม่ ();
ค่าวัตถุ = วัตถุใหม่ ();
อ่อนแอHashMap.put(คีย์, ค่า);
assertTrue(weakHashMap.containsValue(ค่า));
คีย์ = โมฆะ;
System.gc();
-
* รอให้รายการที่ไม่ถูกต้องเข้าสู่ ReferenceQueue เพื่อให้สามารถล้างข้อมูลเหล่านี้ได้ในครั้งต่อไปที่ getTable ถูกเรียก
-
เธรด.สลีป(1,000);
-
* เมื่อไม่มีการอ้างอิงที่ชัดเจนถึงคีย์ WeakHashMap จะลบรายการที่เกี่ยวข้องโดยอัตโนมัติหลังจาก GC
-
assertFalse(weakHashMap.containsValue(ค่า));
-
3.ซอฟท์อ้างอิง
SoftReference โดยพื้นฐานแล้วมีลักษณะเหมือนกับ WeakReference ความแตกต่างที่ใหญ่ที่สุดคือ SoftReference จะเก็บการอ้างอิงไว้นานที่สุดจนกว่า JVM จะหมดหน่วยความจำก่อนที่จะรีไซเคิล (การรับประกันเครื่องเสมือน)
คัดลอกรหัสรหัส ดังต่อไปนี้:
@ทดสอบ
softReference เป็นโมฆะสาธารณะ () {
การอ้างอิงวัตถุ = วัตถุใหม่ ();
SoftReference<Object> softRerference = ใหม่ SoftReference<Object>(อ้างอิง);
assertNotNull(softRerference.get());
อ้างอิง = null;
System.gc();
-
* การอ้างอิงแบบซอฟต์จะถูกรีไซเคิลก่อน jvm OutOfMemory เท่านั้น ดังนั้นจึงเหมาะมากสำหรับแอปพลิเคชันแคช
-
assertNotNull(softRerference.get());
-
4. การอ้างอิง Phantom
ในฐานะตัวเอกของบทความนี้ Phantom Reference แตกต่างจาก WeakReference และ SoftReference อย่างมาก เนื่องจากเมธอด get() จะคืนค่า null เสมอ ซึ่งเป็นที่มาของชื่อ
รหัสจาวา
คัดลอกรหัสรหัส ดังต่อไปนี้:
@ทดสอบ
โมฆะสาธารณะ phantomReferenceAlwaysNull () {
การอ้างอิงวัตถุ = วัตถุใหม่ ();
PhantomReference<Object> phantomReference = ใหม่ PhantomReference<Object>(อ้างอิง ใหม่ ReferenceQueue<Object>());
-
* วิธีการ get ของการอ้างอิง phantom จะคืนค่า null เสมอ
-
assertNull(phantomReference.get());
-
คุณอาจถามว่าอะไรคือการใช้การอ้างอิงที่ส่งคืนค่าว่างเสมอ โปรดใส่ใจกับพารามิเตอร์ตัวที่สอง ReferenceQueue เมื่อสร้าง PhantomReference (อันที่จริง WeakReference & SoftReference ก็สามารถมีพารามิเตอร์นี้ได้)
การใช้ PhantomReference เพียงอย่างเดียวคือการติดตามเมื่อผู้อ้างอิงถูกจัดคิวไว้ใน ReferenceQueue
5. คิวความเกี่ยวข้อง
เมื่อ WeakReference เริ่มส่งกลับค่า null วัตถุที่ชี้ไปก็พร้อมที่จะรีไซเคิลแล้ว ในขณะนี้ สามารถดำเนินการล้างข้อมูลที่เหมาะสมได้ ส่งผ่าน ReferenceQueue ไปยังตัวสร้างของการอ้างอิง เมื่อวัตถุถูกรีไซเคิล เครื่องเสมือน จะถูกแทรกลงใน ReferenceQueue โดยอัตโนมัติ WeakHashMap ใช้ ReferenceQueue เพื่อล้างรายการที่มีคีย์ไม่มีการอ้างอิงที่รัดกุมอีกต่อไป
รหัสจาวา
คัดลอกรหัสรหัส ดังต่อไปนี้:
@ทดสอบ
โมฆะสาธารณะ ReferenceQueue () พ่น InterruptedException {
การอ้างอิงวัตถุ = วัตถุใหม่ ();
ReferenceQueue<Object> ReferenceQueue = ใหม่ ReferenceQueue<Object>();
WeakReference<Object>อ่อนแอReference = ใหม่ WeakReference<Object>(อ้างอิง, ReferenceQueue);
assertFalse(weakReference.isEnqueued());
การอ้างอิง <? ขยายวัตถุ> ถึงขนาด = ReferenceQueue.poll();
assertNull (โพล);
อ้างอิง = null;
System.gc();
assertTrue(weakReference.isEnqueued());
การอ้างอิง<? ขยายวัตถุ> ถูกลบออก = ReferenceQueue.remove();
assertNotNull (ลบออก);
-
6. PhantomReference กับ WeakReference
PhantomReference มีประโยชน์สองประการ ประการแรก ช่วยให้เราทราบได้อย่างแน่ชัดว่าเมื่อใดที่วัตถุถูกลบออกจากหน่วยความจำ
ประการที่สอง สามารถหลีกเลี่ยงปัญหาพื้นฐานบางประการที่เกิดจากการสรุปผลได้ ดังที่กล่าวไว้ข้างต้น ฟังก์ชันเดียวของ PhantomReference คือการติดตามเมื่อผู้อ้างอิงถูกจัดคิวไว้ใน ReferenceQueue แต่ WeakReference ยังมีฟังก์ชันที่เกี่ยวข้องกันอีกด้วย
นี่เป็นเกี่ยวกับวิธีการสรุปของ Object วิธีการนี้จะถูกเรียกก่อนที่จะดำเนินการ gc หากวัตถุโอเวอร์โหลดวิธีการสรุปและจงใจสร้างการอ้างอิงที่ชัดเจนถึงตัวเองภายในวิธีการนี้ จะทำให้ GC รอบนี้ไม่สามารถ รีไซเคิล ออบเจ็กต์นี้อาจทำให้เกิด GC ใดๆ ผลลัพธ์สุดท้ายคือมี Garbage จำนวนมากใน JVM แต่การใช้ PhantomReference สามารถหลีกเลี่ยงปัญหานี้ได้ เนื่องจาก PhantomReference จะถูกรีไซเคิลหลังจากดำเนินการวิธีการสรุปแล้ว ซึ่งหมายความว่าไม่มี ใช้ได้นานกว่านี้แล้วบางทีถ้าเราได้รับข้อมูลอ้างอิงดั้งเดิมปัญหาข้างต้นก็จะไม่เกิดขึ้นแน่นอนนี่เป็นตัวอย่างที่รุนแรงมากและโดยทั่วไปจะไม่เกิดขึ้น
7. การเปรียบเทียบ
การอ้างอิงแบบอ่อน vs อ่อนแอ และ Phantom | ||||
---|---|---|---|---|
พิมพ์ | วัตถุประสงค์ | ใช้ | เมื่อ GCed | การดำเนินการชั้นเรียน |
การอ้างอิงที่แข็งแกร่ง | การอ้างอิงทั่วไป ทำให้วัตถุคงอยู่ตราบใดที่มีการอ้างอิง | การอ้างอิงปกติ | วัตถุใดๆ ที่ไม่ได้ชี้ไปสามารถเรียกคืนได้ | ค่าเริ่มต้น |
การอ้างอิงแบบอ่อน | รักษาวัตถุให้คงอยู่หากมีหน่วยความจำเพียงพอ | เพื่อรักษาอ็อบเจ็กต์ให้คงอยู่แม้ว่าไคลเอ็นต์จะลบการอ้างอิงของตนแล้ว (แคชที่ไวต่อหน่วยความจำ) ในกรณีที่ไคลเอ็นต์เริ่มถามอีกครั้งด้วยคีย์ | หลังจากผ่าน gc ครั้งแรก JVM ตัดสินใจว่ายังคงต้องเรียกคืนพื้นที่เพิ่มเติม | java.lang.ref.SoftReference |
การอ้างอิงที่อ่อนแอ | รักษาวัตถุให้คงอยู่เฉพาะในขณะที่ไคลเอ็นต์ใช้งาน (เข้าถึงได้) เท่านั้น | คอนเทนเนอร์ที่ลบออบเจ็กต์โดยอัตโนมัติไม่ได้ใช้งานอีกต่อไป | หลังจาก gc กำหนดว่าวัตถุนั้นเข้าถึงได้ไม่มากเท่านั้น | java.lang.ref.WeakReference java.util.WeakHashMap |
การอ้างอิงผี | ช่วยให้คุณทำความสะอาดหลังจากการสรุป แต่ก่อนที่พื้นที่จะถูกเรียกคืน (แทนที่หรือเพิ่มการใช้งาน offinalize()) | กระบวนการทำความสะอาดแบบพิเศษ | หลังจากสรุปผลแล้ว | java.lang.ref.PhantomReference |
8. สรุป
แอปพลิเคชันทั่วไปจะไม่เกี่ยวข้องกับการเขียนโปรแกรมอ้างอิง แต่การทำความเข้าใจความรู้นี้จะเป็นประโยชน์ในการทำความเข้าใจหลักการทำงานของ GC และการปรับแต่งประสิทธิภาพ นอกจากนี้ยังอาจใช้เมื่อใช้งานสิ่งอำนวยความสะดวกพื้นฐานบางอย่าง เช่น การแคช ฉันหวังว่าบทความนี้จะมีประโยชน์