1. ประเภทการอ้างอิง (ไม่รวมการอ้างอิงที่แข็งแกร่ง)
สามารถเข้าใจได้ว่าคลาสย่อยโดยตรงของการอ้างอิงถูกประมวลผลโดย JVM ดังนั้นจึงไม่มีผลในการสืบทอดประเภทการอ้างอิงโดยตรงในรหัส มันสามารถสืบทอดได้จากคลาสย่อยเท่านั้น ประเภท subclass ที่สอดคล้องกันรวมถึงสิ่งต่อไปนี้ (ไม่สนใจสิ่งที่ไม่ได้ใช้ใน Java เช่น JNirement)
การประนีประนอม
ความอ่อนแอ
การอ้างอิงขั้นสุดท้าย
การอ้างสิทธิ์
ประเภทอ้างอิงข้างต้นยังถูกกล่าวถึงใน Javadoc ที่เกี่ยวข้อง FinalReference ได้รับการออกแบบมาเป็นพิเศษสำหรับวิธีการสรุปและมีสถานการณ์แอปพลิเคชันอื่น ๆ อีกหลายสถานการณ์ ในหมู่พวกเขามีการใช้ softreference ในแคชที่เกี่ยวข้องกับหน่วยความจำ weakreference ใช้ในสถานการณ์ส่วนใหญ่ที่เกี่ยวข้องกับการรีไซเคิล Phantomreference ใช้ในสถานการณ์การโทรกลับสำหรับการรีไซเคิลวัตถุบรรจุภัณฑ์ (เช่นการตรวจจับการรั่วไหลของทรัพยากร)
คุณสามารถดูข้อมูล subclass ของหลายประเภทใน IDE โดยตรงเพื่อทำความเข้าใจกับสถานการณ์ใดที่ใช้ในกรอบส่วนใหญ่โดยสืบทอดประเภทที่เกี่ยวข้องเพื่อให้เราสามารถทำการประมวลผลการเลือกประเภทได้
2. ตัวสร้างอ้างอิง
มันมีสองตัวสร้างภายในหนึ่งที่มีคิวและอื่น ๆ โดยไม่มีคิว ความหมายของคิวคือเราสามารถตรวจสอบคิวนี้ภายนอก นั่นคือถ้าวัตถุกำลังจะถูกรีไซเคิลวัตถุอ้างอิงที่เกี่ยวข้องจะถูกวางไว้ในคิวนี้ เมื่อเราได้รับการอ้างอิงเราสามารถทำธุรกรรมเพิ่มเติมได้
หากคุณไม่ทำเช่นนั้นคุณสามารถฝึกอบรมวัตถุอ้างอิงได้อย่างต่อเนื่องและตัดสินว่าการรับกลับเป็นโมฆะ (วัตถุ phantomreference ไม่สามารถทำสิ่งนี้ได้หรือไม่ ทั้งสองวิธีมีสถานการณ์การใช้งานที่สอดคล้องกันขึ้นอยู่กับแอปพลิเคชันจริง ตัวอย่างเช่นใน beakhashmap คุณเลือกที่จะสอบถามข้อมูลคิวเพื่อตรวจสอบว่าวัตถุใดจะถูกนำกลับมาใช้ใหม่หรือไม่ สำหรับ ThreadLocalMap ใช้เพื่อตรวจสอบว่า GET () เป็นโมฆะสำหรับการประมวลผลหรือไม่
ตัวสร้างที่เกี่ยวข้องมีดังนี้:
การอ้างอิง (การอ้างอิง t) {สิ่งนี้ (อ้างอิง, null);} การอ้างอิง (t อ้างอิง, referenceQueue <? super t> queue) {this.referent = อ้างอิง; this.queue = (queue == null)? ReferenceQueue.null: คิว;}คิวโมฆะที่นี่สามารถเข้าใจได้ว่าเป็นคิวที่ไม่ต้องการการประมวลผลข้อมูลใด ๆ ในคิว และจะไม่เข้าถึงข้อมูลใด ๆ ภายใน
ในวัตถุข้างต้นการอ้างอิงแสดงถึงวัตถุที่อ้างอิงนั่นคือวัตถุที่เราต้องห่อเมื่อเราสร้างมัน คำจำกัดความที่ว่าวัตถุกำลังจะรีไซเคิลหมายความว่าวัตถุนี้ไม่มีการอ้างอิงอื่นยกเว้นการอ้างอิง (ไม่ใช่ว่ามันไม่ได้อ้างอิงจริง ๆ แต่การเข้าถึง GCROOT นั้นไม่สามารถเข้าถึงได้เพื่อหลีกเลี่ยงปัญหาการอ้างอิงแบบวงกลม)
คิวคือคิวที่จะได้รับแจ้งเมื่อวัตถุถูกรีไซเคิล เมื่อวัตถุถูกรีไซเคิลวัตถุอ้างอิงทั้งหมด (ไม่ใช่วัตถุรีไซเคิล) จะถูกวางไว้ในคิวจากนั้นโปรแกรมภายนอกสามารถรับข้อมูลที่เกี่ยวข้องได้โดยการตรวจสอบคิวนี้
3. ReferenceQueue และอ้างอิงอ้างอิง
คิวที่นี่เป็นคิวในนาม แต่ไม่มีโครงสร้างการจัดเก็บจริงภายใน ที่เก็บของมันขึ้นอยู่กับความสัมพันธ์ระหว่างโหนดภายใน สามารถเข้าใจได้ว่าคิวเป็นโครงสร้างที่คล้ายกับรายการที่เชื่อมโยงและโหนดที่นี่เป็นข้อมูลอ้างอิงเอง สามารถเข้าใจได้ว่าคิวเป็นคอนเทนเนอร์สำหรับรายการที่เชื่อมโยงซึ่งจะเก็บเฉพาะโหนดหัวปัจจุบันและโหนดที่ตามมาจะถูกเก็บรักษาไว้โดยแต่ละโหนดอ้างอิงเองผ่านถัดไป
ค่าสถานะอ้างอิง
วัตถุอ้างอิงแต่ละรายการมีคำอธิบายสถานะที่สอดคล้องกันนั่นคือมันอธิบายตัวเองและวัตถุที่ห่อหุ้มอยู่ในปัจจุบันเพื่อความสะดวกในการสืบค้นการวางตำแหน่งหรือการประมวลผล
1. แอคทีฟ: สถานะที่ใช้งานอยู่นั่นคือวัตถุที่เกี่ยวข้องเป็นสถานะอ้างอิงที่แข็งแกร่งและยังไม่ได้รีไซเคิล ในสถานะนี้วัตถุจะไม่ถูกวางไว้ในคิว ในสถานะนี้ถัดไปเป็นโมฆะและคิวคือคิวที่อ้างอิงเมื่อมีการกำหนด
2. รอดำเนินการ: เตรียมที่จะวางไว้ในคิว ในสถานะนี้วัตถุที่จะประมวลผลจะถูกคิวทีละคนในคิว ในช่วงเวลานี้หน้าต่างวัตถุที่เกี่ยวข้องอยู่ในสถานะที่รอดำเนินการ ไม่ว่าคุณจะเข้าสู่สถานะนี้คุณสามารถคิดได้ว่าในสถานะที่สอดคล้องกันถัดไปคือตัวเอง (กำหนดโดย JVM) และคิวคือคิวที่อ้างอิงเมื่อมีการกำหนด
3. enqueued: วัตถุที่เกี่ยวข้องจะถูกรีไซเคิลแล้วและวัตถุอ้างอิงที่เกี่ยวข้องได้ถูกวางไว้ในคิว เธรดภายนอกพร้อมที่จะสอบถามคิวเพื่อรับข้อมูลที่เกี่ยวข้อง ในสถานะนี้ถัดไปเป็นวัตถุถัดไปที่จะประมวลผลและคิวเป็นวัตถุบัตรประจำตัวพิเศษที่ถูก enqueued
4. ไม่ได้ใช้งาน: นั่นคือวัตถุนี้ได้รับการดึงมาจากคิวจากภายนอกและได้รับการประมวลผล นั่นหมายความว่าวัตถุอ้างอิงนี้สามารถนำกลับมาใช้ใหม่ได้และวัตถุที่ห่อหุ้มภายในสามารถนำกลับมาใช้ใหม่ได้ (การดำเนินการรีไซเคิลจริงขึ้นอยู่กับว่าการกระทำที่ชัดเจนเรียกว่า) สามารถเข้าใจได้ว่าผู้ที่เข้าสู่สถานะนี้จะต้องรีไซเคิล
JVM ไม่จำเป็นต้องกำหนดค่าสถานะเพื่อพิจารณาว่าสถานะการอ้างอิงที่สอดคล้องกันอยู่ในนั้นจำเป็นต้องคำนวณเพียงครั้งต่อไปและคิวเพื่อตัดสิน
4. ReferenceQueue#head
บันทึกโหนดล่าสุดที่จะประมวลผลในคิวปัจจุบันเสมอ คุณสามารถพิจารณาคิวเป็นคิวครั้งสุดท้าย เมื่อโหนดใหม่เข้าสู่ตรรกะต่อไปนี้จะถูกนำมาใช้
newe.next = head; head = newe;
จากนั้นเมื่อได้รับให้ใช้ตรรกะที่เกี่ยวข้อง
tmp = head; head = tmp.next; return tmp;
V. อ้างอิง#ถัดไป
นั่นคืออธิบายโหนดถัดไปที่จัดเก็บโดยโหนดอ้างอิงที่กำลังจะถูกประมวลผล แต่ถัดไปจะสมเหตุสมผลเมื่อวางไว้ในคิว เพื่ออธิบายค่าสถานะที่สอดคล้องกันหลังจากถูกวางไว้ในคิวคิวของมันจะไม่อ้างถึงคิวอีกต่อไป แต่จะอ้างถึงการเสริมความพิเศษ เนื่องจากมันถูกวางไว้ในคิวจึงไม่ถูกวางไว้ในคิวอีกครั้ง
6. การอ้างอิง#อ้างอิง
นั่นคืออธิบายวัตถุจริงที่อ้างอิงโดยการอ้างอิงปัจจุบันซึ่งจะดำเนินการอย่างระมัดระวังตามที่ระบุไว้ในคำอธิบายประกอบ นั่นคือเมื่อสิ่งนี้จะรีไซเคิลและถ้ามีการรีไซเคิลมันจะถูกตั้งค่าโดยตรงเป็นโมฆะและโปรแกรมภายนอกสามารถเรียนรู้จากวัตถุอ้างอิงเอง (แทนที่จะอ้างอิง) ว่าพฤติกรรมการรีไซเคิลเกิดขึ้น
7. ReferenceQueue#enqueue รอการอ้างอิง enqueue
กระบวนการนี้เป็นกระบวนการของวัตถุอ้างอิงจาก active-> agending-> enqued วิธีนี้คือการประมวลผลวัตถุที่จัดการสถานะที่ค้างอยู่เป็นสถานะที่ถูกยึด กระบวนการที่สอดคล้องกันคือตรรกะก่อนหน้านั่นคือโหนดถูกยกเลิกและรหัสที่เกี่ยวข้องมีดังนี้
r.queue = enqueued; r.next = (head == null)? R: head; head = r; queuelength ++; lock.notifyall ();
Nitify สุดท้ายหมายถึงการแจ้งโปรแกรมภายนอกที่บล็อกในคิวปัจจุบันก่อน (นั่นคือวัตถุที่ค้างอยู่ยังไม่ได้รับมาก่อน)
8. การอ้างอิง#tryhandlepending
นั่นคือมันจัดการการเปลี่ยนแปลงของวัตถุอ้างอิงจากการใช้งานไปเป็นสถานะที่รอดำเนินการ ภายในวัตถุอ้างอิงมีฟิลด์คงที่และการประกาศที่สอดคล้องกันมีดังนี้:
/* รายการการอ้างอิงที่รอการแต่ง ตัวสะสมเพิ่ม * การอ้างอิงไปยังรายการนี้ในขณะที่เธรดอ้างอิงอ้างอิงจะลบออก * รายการนี้ได้รับการปกป้องโดยวัตถุล็อคข้างต้น รายการ * ใช้ฟิลด์ที่ค้นพบเพื่อเชื่อมโยงองค์ประกอบของมัน */การอ้างอิงแบบคงที่ส่วนตัว <Object> รออยู่ = null;
สามารถเข้าใจได้ว่า JVM จะทำให้วัตถุถูกประมวลผลในฟิลด์คงที่นี้เมื่อ GC ในเวลาเดียวกันฟิลด์อื่นที่ค้นพบแสดงถึงวัตถุต่อไปของวัตถุที่จะประมวลผล นั่นคือมันสามารถเข้าใจได้ว่าวัตถุที่จะประมวลผลนั้นเป็นรายการที่เชื่อมโยง มันถูกคิวผ่านการค้นพบ คุณจะต้องรอดำเนินการต่อไปจากนั้นรับวัตถุต่อไปอย่างต่อเนื่องผ่านการค้นพบ เนื่องจากเธรดทั้งสองอาจเข้าถึงวัตถุที่รอดำเนินการนี้จึงจำเป็นต้องใช้การประมวลผลล็อค
กระบวนการประมวลผลที่สอดคล้องกันมีดังนี้:
if (รอดำเนินการ! = null) {r = รอดำเนินการ; // 'อินสแตนซ์' อาจโยน outofmemoryError บางครั้ง // ทำเช่นนี้ก่อนที่จะยกเลิกการเชื่อมโยง 'r' จากโซ่ 'รอดำเนินการ' ... c = r อินสแตนซ์ของน้ำยาทำความสะอาด? (ทำความสะอาด) r: null; // unlink 'r' จาก 'รอคอย' ที่รอดำเนินการ = r.discovered; r.discovered = null;} // enqueue วัตถุการประมวลผลนั่นคือมันเข้าสู่การอ้างอิงสถานะ enqued <? Super Object> q = r.queue; if (q! = referencequeue.null) q.enqueue (r);9. อ้างอิง#เคลียร์
ล้างวัตถุต้นฉบับที่อ้างอิงโดยวัตถุอ้างอิงเพื่อให้วัตถุต้นฉบับไม่สามารถเข้าถึงได้ผ่านวิธี Get () อีกต่อไป จากแนวคิดการออกแบบที่สอดคล้องกันเนื่องจากได้ป้อนวัตถุคิวหมายความว่าวัตถุที่เกี่ยวข้องจะต้องรีไซเคิลเนื่องจากไม่จำเป็นต้องเข้าถึงวัตถุต้นฉบับอีกครั้ง วิธีนี้จะไม่ถูกเรียกโดย JVM และ JVM จะล้างข้อมูลอ้างอิงที่สอดคล้องกันโดยตรงผ่านการดำเนินการของฟิลด์และการใช้งานเฉพาะนั้นสอดคล้องกับวิธีการปัจจุบัน
ความหมายที่ชัดเจนคือการอ้างอิง
หลังจากวัตถุที่อ่อนแอลงในคิวการอ้างอิงที่สอดคล้องกันนั้นเป็นโมฆะ
วัตถุ Softreference หากวัตถุไม่เข้าคิวเมื่อหน่วยความจำเพียงพอการอ้างอิงที่สอดคล้องกันจะไม่เป็นโมฆะ หากจำเป็นต้องประมวลผล (ไม่เพียงพอหน่วยความจำหรือนโยบายอื่น ๆ ) การอ้างอิงที่เกี่ยวข้องจะถูกตั้งค่าเป็น NULL แล้วป้อนคิว
วัตถุ Finalreference เนื่องจากจำเป็นต้องเรียกวัตถุสุดท้ายแม้ว่าการอ้างอิงจะถูกป้อนลงในคิวการอ้างอิงของมันจะไม่เป็นโมฆะนั่นคือมันจะไม่ถูกล้าง
วัตถุ phantomreference เนื่องจากตัวเองถูกนำไปใช้เพื่อคืนค่า null นั้นไม่ได้มีประโยชน์มาก เพราะมันจะไม่ถูกล้างไม่ว่าจะเป็น enqueue หรือไม่ก็ตาม
10. ด้าย enqueue referenthandler enqueue
ดังที่ได้กล่าวไว้ข้างต้น JVM จะตั้งค่าวัตถุที่จะประมวลผลเป็นวัตถุที่ค้างอยู่ดังนั้นจะต้องมีเธรดเพื่อดำเนินการ enqueue อย่างต่อเนื่อง เธรดนี้หมายถึงเธรดโปรเซสเซอร์และลำดับความสำคัญของมันคือ max_priority นั่นคือสูงสุด กระบวนการเริ่มต้นที่สอดคล้องกันถูกสร้างขึ้นเริ่มต้นแบบคงที่ซึ่งสามารถเข้าใจได้ว่าเมื่อใช้วัตถุหรือคลาสอ้างอิงใด ๆ เธรดนี้จะถูกสร้างและเริ่มต้น รหัสที่เกี่ยวข้องมีดังนี้:
Static {ThreadGroup tg = thread.currentthread (). getThreadGroup (); สำหรับ (threadGroup tgn = tg; tgn! = null; tg = tgn, tgn = tg.getParent ()); เธรด Handler = ใหม่ ReferenceHandler (TG, "Handler อ้างอิง"); / * หากมีลำดับความสำคัญของระบบพิเศษมากกว่า * max_priority มันจะถูกใช้ที่นี่ */ handler.setPriority (thread.max_priority); handler.setdaemon (จริง); handler.start ();}ลำดับความสำคัญของมันคือสูงสุดซึ่งสามารถเข้าใจได้ว่าจำเป็นต้องประมวลผลวัตถุอ้างอิงอย่างต่อเนื่อง เมื่อพิมพ์เธรดที่รันผ่าน JSTACK ตัวจัดการอ้างอิงที่สอดคล้องกันหมายถึงเธรดที่เริ่มต้นที่นี่ดังที่แสดงด้านล่าง:
11. JVM ที่เกี่ยวข้อง
ในแต่ละจุดประมวลผลข้างต้นพวกเขาเกี่ยวข้องกับกระบวนการรีไซเคิล JVM นั่นคือเชื่อว่ากระบวนการ GC จะทำงานร่วมกับการอ้างอิงที่สอดคล้องกัน ตัวอย่างเช่นการใช้ CMS Collector กระบวนการ preclean มีส่วนร่วมในกระบวนการทั้งหมดที่กล่าวถึงข้างต้นและการประมวลผลหมายเหตุ softreference ฯลฯ ในเวลาเดียวกันการประมวลผลต่าง ๆ ของวัตถุอ้างอิงจะต้องเกี่ยวข้องกับประเภทที่เฉพาะเจาะจง การประมวลผล JVM ที่สอดคล้องกันใช้รหัส C ++ ดังนั้นจึงจำเป็นต้องมีการจัดเรียงอย่างระมัดระวัง
12. สรุป
เช่นเดียวกับวัตถุ FinalEference การอ้างอิงทั้งหมดและการอ้างอิงเป็นกลุ่มของกลุ่มการประมวลผลที่ทำงานร่วมกัน เพื่อให้แน่ใจว่ามีความหมายอ้างอิงที่แตกต่างกันกระบวนการที่เกี่ยวข้องกับ JVM GC ได้รับการรับรู้ในที่สุดสำหรับสถานการณ์ที่แตกต่างกันและระดับการอ้างอิงที่แตกต่างกัน
นอกจากนี้เนื่องจากการใช้อ้างอิงโดยตรงและการเปิดเธรดเพื่อตรวจสอบคิวนั้นลำบากและซับซ้อนเกินไป คุณสามารถอ้างถึง FinalizableReferenceQueue ที่ใช้โดย Google Guava และวัตถุ Finalizablereference ที่เกี่ยวข้อง กระบวนการประมวลผลสามารถทำให้ง่ายขึ้นเล็กน้อย ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้และฉันหวังว่ามันจะนำความช่วยเหลือมาสู่การเรียนรู้หรือการทำงานของทุกคน