คำพูด FinalEference
คลาสนี้เป็นประเภทแพ็คเกจซึ่งระบุว่าไม่ใช่ส่วนสาธารณะและสืบทอดมาจากการอ้างอิงซึ่งหมายความว่ามันเป็นประเภทอ้างอิงที่เฉพาะเจาะจง ดังนั้นก่อนที่วัตถุแต่ละชิ้นจะถูกนำไปรีไซเคิลมันจะถูกวางไว้ใน referqyebcequeue ที่ระบุ
วัตถุอ้างอิงนี้ใช้โดยเฉพาะสำหรับคลาสที่มีวิธีการสรุป สามารถเข้าใจได้ว่าวัตถุทุกชิ้นที่มีวิธีการที่สอดคล้องกันจะถูกห่อหุ้มเป็นวัตถุ Finalrefernece
เนื่องจากวิธีการสุดท้ายถูกกำหนดโดยวัตถุการใช้งานเริ่มต้นของมันจึงว่างเปล่า จากนั้นหากวิธีการนี้ถูกเขียนใหม่วิธีการจะไม่ว่างเปล่าแน่นอน ความแตกต่างนี้สามารถทำได้ผ่านสิ่งนี้ ตราบใดที่วิธีการสุดท้ายใช้คลาสที่ไม่ว่างเปล่าวัตถุที่สร้างขึ้นจะต้องลงทะเบียนใน Finalrefernece
ขั้นตอนนี้สามารถลงทะเบียนได้ตามการเรียกใช้วิธีการสร้างตัวสร้างวัตถุในช่วง Newinstance
Finalizer#วิธีการลงทะเบียน
เมื่อวิธีนี้เรียกว่าส่วนใหญ่วัตถุ finalizer ที่เกี่ยวข้องจะถูกสร้างขึ้นและวัตถุสุดท้ายจะสืบทอดมาจาก FinalEference วิธีนี้ประกาศดังนี้:
/ * เรียกใช้โดย VM */static void register (object finalizee) {ใหม่ finalizer (finalizee);} ดังที่เห็นได้จากความคิดเห็นข้างต้นวิธีนี้จะถูกเรียกโดย JVM ในช่วงเวลาที่กำหนด
จากนั้นเปลี่ยนเป็นตัวสร้างของ Finalizer ดังที่แสดงด้านล่าง:
private finalizer (วัตถุ finalizee) {super (finalizee, คิว); เพิ่ม();} จะเห็นได้ว่าวัตถุอ้างอิงที่เกี่ยวข้องจะถูกเรียกกลับผ่านคิว ฟังก์ชั่นของการเพิ่มคือการบันทึกวัตถุทั้งหมดที่ยังไม่จบวิธีการและเรียกมันที่ System.shutdown สิ้นสุด Shutdown ตั้งค่าผ่าน Runtime#runFinalizersOnExit
อ้างอิง
คิวการอ้างอิงนี้จะถูกวางไว้ในคิวนี้ก่อนที่วัตถุภายในของวัตถุอ้างอิงที่เกี่ยวข้องจะถูกนำกลับมาใช้ใหม่ (คำอธิบายโดยละเอียดจะถูกอธิบายในบทความอื่นเกี่ยวกับการอ้างอิง) เนื่องจากเฉพาะวัตถุที่เกี่ยวข้องเท่านั้นที่จะได้รับจากคิวนี้
จากนั้นเรียกใช้วิธีการสรุปที่สอดคล้องกันก่อนรีไซเคิล
เธรด finalizerThread
เธรดนี้เก็บข้อมูลจากคิวจากนั้นเรียกใช้วิธีการสรุปที่สอดคล้องกัน รหัสที่เกี่ยวข้องมีดังนี้:
สำหรับ (;;) {ลอง {finalizer f = (finalizer) queue.remove (); F.Runfinalizer (JLA); } catch (interruptedException x) {// ละเว้นและดำเนินการต่อ}}}runfinalizer ที่เกี่ยวข้องมีดังนี้:
ซิงโครไนซ์ (นี่) {ถ้า (hasbeenfinalized ()) กลับ; ลบ ();} ลอง {object finalize = this.get (); if (finalizee! = null &&! (finalizee instanceof java.lang.enum)) {jla.invokefinalize (finalizee); / * สล็อตสแต็กล้างที่มีตัวแปรนี้เพื่อลดโอกาสในการเก็บรักษาเท็จด้วย GC */ finalizee = null; }} catch (throwable x) {} super.clear ();ในตรรกะด้านบนการโทรครั้งแรกลบและลบออกจากขั้นสุดท้าย วิธีนี้คือเพื่อให้แน่ใจว่าการสรุปของแต่ละวัตถุจะถูกเรียกเพียงครั้งเดียวมากที่สุดนั่นคือการโทรปัจจุบันเสร็จสมบูรณ์ มันจะถูกบันทึกไว้ในสถานะที่สอดคล้องกันนั่นคือ Hasbeenfinalized กลับมาเป็นจริง (ในความเป็นจริงมันหมายถึงการชี้ตัวชี้ต่อไปในตัวของมันเองนั่นคือมันไม่เคยเสร็จสิ้นและไม่จำเป็นต้องเรียกจบอีกครั้ง)
ถัดไปคือการเรียกวิธีการสรุปที่สอดคล้องกัน jla.invokeFinalize ด้านบนจริง ๆ แล้วเรียกใช้วิธีสุดท้ายของวัตถุที่เกี่ยวข้อง ในกระบวนการนี้วัตถุต้นฉบับจะได้รับผ่าน GET เป็นครั้งแรก ในกระบวนการ JVM ทั้งหมดการอ้างอิงจะไม่ถูกตั้งค่าเป็น NULL ก่อนที่จะรีไซเคิลสำหรับ FinalizeReference เพราะที่นี่สามารถรับวัตถุอ้างอิงที่เกี่ยวข้องได้เสมอ
หลังจากการประมวลผลความชัดเจนที่สอดคล้องกันจะถูกเรียกในที่สุดเพื่อล้างข้อมูลอ้างอิงที่เกี่ยวข้อง สิ่งนี้บรรลุผลของการอ้างอิงขั้นสุดท้ายที่ไม่มีวัตถุอื่นที่จะอ้างอิง
ในการประมวลผลข้างต้นไม่มีการ จำกัด เวลาในการโทรสรุป ดังนั้นเมื่อการสรุปวัตถุสุดท้ายเรียกว่าช้ามันจะส่งผลกระทบต่อการดำเนินการของห่วงโซ่การรีไซเคิลทั้งหมดและจะมีการสร้างข้อยกเว้น OOM ที่สอดคล้องกัน ดังนั้นเว้นแต่ในกรณีพิเศษอย่าเขียนสรุปใหม่ ควรมีวิธีอื่นในการจัดการกับสถานการณ์ที่เกี่ยวข้อง ตัวอย่างเช่น finalizablereference ใน Guava
Finalizer เริ่มต้นเธรด
ในเธรดข้างต้นจะเริ่มต้นในระหว่างการเริ่มต้นกระบวนการที่สอดคล้องกัน สามารถเข้าใจได้ว่าวัตถุจะกระตุ้นการเริ่มต้นของคลาส finalizer โดยการโทร register(object) จากนั้นในบล็อกการเริ่มต้นแบบคงที่เธรดรีไซเคิลที่สอดคล้องกันจะเริ่มต้นขึ้น รหัสเริ่มต้นที่สอดคล้องกันมีดังนี้:
Static {ThreadGroup tg = thread.currentthread (). getThreadGroup (); สำหรับ (threadGroup tgn = tg; tgn! = null; tg = tgn, tgn = tg.getParent ()); เธรด finalizer = ใหม่ finalizerThread (TG); finalizer.setPriority (thread.max_priority - 2); finalizer.setdaemon (จริง); finalizer.start ();}สแตติกด้านบนเป็นบล็อกการเริ่มต้นแบบคงที่นั่นคือตราบใดที่การใช้คลาสสุดท้ายของคลาสจะถูกเรียกใช้การโทรที่สอดคล้องกันจะถูกทริกเกอร์ กลุ่มเธรดที่ใช้ที่นี่คือกลุ่มเธรดระบบและลำดับความสำคัญยังค่อนข้างสูงและได้รับการกำหนดค่าเป็นเธรดพื้นหลัง
เมื่อใช้ JStack เพื่อพิมพ์เธรดเธรดที่แสดงด้านล่างรูปจะเริ่มขึ้นที่นี่ ดังแสดงในรูปด้านล่าง
สรุป
Finalizer ทั้งหมดทำงานร่วมกันผ่าน FinalReference โดย JVM และคลาส Java ที่สอดคล้องกัน มันไม่ได้ถูกนำไปใช้โดย JVM ทั้งหมดดังนั้นจึงสามารถพิจารณาได้ว่ามันไม่ได้เป็นพื้นฐานเกินไป แต่เพื่อใช้ความหมายที่สอดคล้องกัน ทุกอย่างทำโดย Java ปกติและให้ความร่วมมือโดย JVM การทำความเข้าใจกระบวนการทั้งหมดก็เป็นความเข้าใจในกลไกการทำงานของชวาเอง