ฉันจำเป็นต้องทราบเมื่อมีการใช้วิธีการที่เรียกว่าในfinalize()
JVM
ฉันสร้างคลาสทดสอบซึ่งเขียนลงในไฟล์เมื่อมีfinalize()
การเรียกเมธอดโดยลบล้างมัน มันไม่ได้ดำเนินการ ใครช่วยบอกฉันได้ว่าทำไมมันถึงไม่ทำงาน?
finalize()
และการรวบรวมขยะไม่มีผลกระทบใด ๆ
ฉันจำเป็นต้องทราบเมื่อมีการใช้วิธีการที่เรียกว่าในfinalize()
JVM
ฉันสร้างคลาสทดสอบซึ่งเขียนลงในไฟล์เมื่อมีfinalize()
การเรียกเมธอดโดยลบล้างมัน มันไม่ได้ดำเนินการ ใครช่วยบอกฉันได้ว่าทำไมมันถึงไม่ทำงาน?
finalize()
และการรวบรวมขยะไม่มีผลกระทบใด ๆ
คำตอบ:
โดยทั่วไปไม่ควรพึ่งพา finalize()
ทำความสะอาดใด ๆ
ตามที่Javadoc (ซึ่งมันจะคุ้มค่าการอ่าน) ก็คือ:
เรียกว่าโดยตัวรวบรวมขยะบนวัตถุเมื่อการรวบรวมขยะกำหนดว่าไม่มีการอ้างอิงไปยังวัตถุ
ดังที่โจอาคิมชี้ให้เห็นสิ่งนี้อาจไม่เกิดขึ้นในชีวิตของโปรแกรมถ้าวัตถุนั้นเข้าถึงได้ตลอดเวลา
นอกจากนี้ตัวรวบรวมขยะไม่รับประกันว่าจะทำงานในเวลาใดก็ได้ โดยทั่วไปสิ่งที่ฉันพยายามจะพูดfinalize()
อาจไม่ใช่วิธีที่ดีที่สุดในการใช้โดยทั่วไปเว้นแต่จะมีบางอย่างที่คุณต้องการ
finalize
จะมีประโยชน์คืออะไร?
finalize()
วิธีการสำหรับชั้นหลักจะเรียกเมื่อ >> << อินสแตนซ์ของชั้นที่มีการเก็บขยะไม่ได้เมื่อยุติวิธีการหลัก นอกจากนี้คลาสหลักอาจเป็นที่เก็บขยะก่อนที่แอปพลิเคชันจะเสร็จสิ้น เช่นในแอพแบบมัลติเธรดที่เธรด "main" สร้างเธรดอื่นแล้วส่งคืน (ในทางปฏิบัติต้องใช้ classloader ที่ไม่เป็นมาตรฐาน .... )
finalize
วิธีการที่เรียกว่าเมื่อวัตถุเป็นเรื่องเกี่ยวกับที่จะได้รับการเก็บขยะ ซึ่งอาจเป็นเมื่อใดก็ได้หลังจากที่มีสิทธิ์ในการรวบรวมขยะ
โปรดทราบว่าอาจเป็นไปได้ว่าวัตถุไม่เคยได้รับการรวบรวมขยะ finalize
ไม่เคยถูกเรียกเช่นนั้น) สิ่งนี้สามารถเกิดขึ้นได้เมื่อออบเจ็กต์ไม่เคยมีสิทธิ์ใช้งาน gc (เนื่องจากสามารถเข้าถึงได้ตลอดอายุการใช้งานของ JVM) หรือเมื่อไม่มีการรวบรวมขยะจริง ๆ ระหว่างเวลาที่ออบเจ็กต์มีคุณสมบัติและเวลาที่ JVM หยุดทำงาน โปรแกรมทดสอบ)
มีวิธีที่จะบอกให้ JVM ทำงานfinalize
บนวัตถุที่ยังไม่ได้รับการเรียกใช้ แต่การใช้พวกมันยังไม่เป็นความคิดที่ดี (การรับประกันวิธีการนั้นไม่แข็งแรงเช่นกัน)
หากคุณเชื่อมั่นในfinalize
การทำงานที่ถูกต้องของแอปพลิเคชันของคุณแสดงว่าคุณกำลังทำอะไรผิดพลาด finalize
ควรเพียง แต่นำมาใช้สำหรับการทำความสะอาดของ (ปกติไม่ใช่ Java) ทรัพยากร และที่ว่าเพราะ JVM ไม่ได้รับประกันว่าfinalize
เคยเรียกว่าวัตถุใด ๆ
Closable
อินเทอร์เฟซ (และแนวคิดเบื้องหลัง) อาจเป็นสิ่งที่คุณต้องการ: ทำการ.close()
ปิด / ทิ้งทรัพยากรและต้องการให้ผู้ใช้ในชั้นเรียนของคุณเรียกมันในเวลาที่เหมาะสม คุณอาจต้องการเพิ่มfinalize
วิธีการ "เพียงบันทึก" แต่นั่นจะเป็นเครื่องมือการดีบักมากกว่าการแก้ไขที่แท้จริง (เพราะไม่น่าเชื่อถือเพียงพอ)
System.gc()
ใช้ FileInputStream :: finalize () จากนั้นฉันสามารถย้ายไฟล์ได้
protected void finalize() throws Throwable {}
- ทุกคลาสสืบทอด
finalize()
วิธีการจาก java.lang.Object- เมธอดถูกเรียกใช้โดยตัวรวบรวมขยะเมื่อพิจารณาว่าไม่มีการอ้างอิงไปยังวัตถุอีกต่อไป
- วิธีการสรุปวัตถุไม่มีการดำเนินการ แต่อาจถูกแทนที่โดยคลาสใด ๆ
- ปกติแล้วมันควรจะถูกแทนที่เพื่อล้างทรัพยากรที่ไม่ใช่ Java เช่นการปิดไฟล์
ถ้า overridding มันคือการเขียนโปรแกรมที่ดีที่จะใช้คำสั่งลองจับและในที่สุดก็จะโทรเสมอ
finalize()
super.finalize()
นี่เป็นมาตรการด้านความปลอดภัยเพื่อให้แน่ใจว่าคุณไม่พลาดการปิดรีซอร์สที่ใช้โดยคลาสที่เรียกออบเจ็กต์protected void finalize() throws Throwable { try { close(); // close open files } finally { super.finalize(); } }
ข้อยกเว้นใด ๆ ที่ถูกโยนโดย
finalize()
ในระหว่างการรวบรวมขยะหยุดการสรุป แต่จะถูกละเว้นfinalize()
ไม่เคยวิ่งมากกว่าหนึ่งครั้งบนวัตถุใด ๆ
ยกมาจาก: http://www.janeg.ca/scjp/gc/finalize.html
คุณสามารถตรวจสอบบทความนี้:
finalize()
เมธอดJava ไม่ใช่ตัวทำลายและไม่ควรใช้เพื่อจัดการกับตรรกะที่แอ็พพลิเคชันของคุณขึ้นอยู่กับ Java spec ระบุว่าไม่มีการรับประกันว่าfinalize
จะมีการเรียกใช้เมธอดในระหว่างการใช้งานจริงของแอพพลิเคชั่น
สิ่งที่คุณอาจต้องการคือการรวมกันfinally
และวิธีการล้างข้อมูลเช่นเดียวกับใน:
MyClass myObj;
try {
myObj = new MyClass();
// ...
} finally {
if (null != myObj) {
myObj.cleanup();
}
}
ตรวจสอบ Java ที่มีประสิทธิภาพหน้า 2 รุ่น 27 รายการที่ 7: หลีกเลี่ยงขั้นตอนสุดท้าย
Finalizers คาดเดาไม่ได้มักเป็นอันตรายและไม่จำเป็นโดยทั่วไป ไม่เคยทำอะไรที่สำคัญในการเข้ารอบสุดท้าย ไม่เคยขึ้นอยู่กับ finalizer เพื่ออัปเดตสถานะถาวรที่สำคัญ
หากต้องการยุติทรัพยากรให้ลองใช้แทนแทน:
// try-finally block guarantees execution of termination method Foo foo = new Foo(...); try { // Do what must be done with foo ... } finally { foo.terminate(); // Explicit termination method }
เมื่อเป็น
finalize()
วิธีการที่เรียกว่าใน Java?
ขั้นตอนสุดท้ายจะถูกเรียกหลังจาก GC ตรวจพบว่าวัตถุนั้นไม่สามารถเข้าถึงได้อีกต่อไปและก่อนที่มันจะเรียกคืนหน่วยความจำที่ใช้โดยวัตถุ
หากวัตถุไม่สามารถเข้าถึงไม่ได้finalize()
จะไม่มีการเรียกใช้วัตถุนั้น
หาก GC ไม่ทำงานfinalize()
อาจไม่ถูกเรียกใช้ (โดยปกติ GC จะทำงานเฉพาะเมื่อ JVM ตัดสินใจว่ามีแนวโน้มที่ขยะมากพอที่จะทำให้คุ้มค่า)
อาจใช้เวลามากกว่าหนึ่งรอบ GC ก่อนที่ GC จะกำหนดว่าไม่สามารถเข้าถึงวัตถุที่เฉพาะเจาะจงได้ (Java GCs มักจะเป็นนักสะสม "generational" ... )
เมื่อ GC ตรวจพบวัตถุที่ไม่สามารถเข้าถึงได้และสามารถแก้ไขได้มันจะอยู่ในคิวการสรุป การสรุปจะเกิดขึ้นแบบอะซิงโครนัสกับ GC ปกติ
(สเปค JVM จริง ๆ แล้วอนุญาตให้ JVM ไม่เคยทำรัน finalizers ... โดยที่มันไม่ได้เรียกคืนพื้นที่ที่ใช้โดยวัตถุ JVM ที่ใช้งานในลักษณะนี้จะพิการ / ไร้ประโยชน์ แต่พฤติกรรมนี้คือ "อนุญาต" .)
ผลที่สุดคือการไม่เชื่อมั่นในการทำสิ่งต่าง ๆ ที่ต้องทำในกรอบเวลาที่แน่นอน มันเป็น "แนวปฏิบัติที่ดีที่สุด" ที่จะไม่ใช้มันเลย ควรมีวิธีที่ดีกว่า (เช่นเชื่อถือได้มากกว่า) ในการทำสิ่งที่คุณพยายามทำในfinalize()
วิธีนั้น
การใช้อย่างถูกต้องตามกฎหมายสำหรับการจัดทำขั้นสุดท้ายเท่านั้นคือการล้างทรัพยากรที่เกี่ยวข้องกับวัตถุที่รหัสแอปพลิเคชันสูญหาย ถึงอย่างนั้นคุณควรพยายามเขียนรหัสแอปพลิเคชันเพื่อไม่ให้วัตถุหายไปตั้งแต่แรก (ตัวอย่างเช่นใช้ Java 7+ ลองกับทรัพยากรเพื่อให้แน่ใจว่าclose()
ถูกเรียกเสมอ ... )
ฉันสร้างคลาสทดสอบซึ่งเขียนลงในไฟล์เมื่อมีการเรียกใช้เมธอด finalize () โดยการแทนที่ มันไม่ได้ดำเนินการ ใครช่วยบอกฉันได้ว่าทำไมมันถึงไม่ทำงาน?
มันยากที่จะพูด แต่มีความเป็นไปได้ไม่กี่:
เนื่องจากมีความไม่แน่นอนในการเรียกวิธีการสรุป () โดย JVM (ไม่แน่ใจว่าจะจบ () ซึ่งจะถูกแทนที่จะถูกดำเนินการหรือไม่) เพื่อวัตถุประสงค์ในการศึกษาวิธีที่ดีกว่าที่จะสังเกตสิ่งที่เกิดขึ้นเมื่อเรียก (จบ) คือ บังคับ JVM System.gc()
ที่จะเรียกเก็บขยะโดยคำสั่ง
โดยเฉพาะอย่างยิ่ง finalize () จะถูกเรียกเมื่อวัตถุไม่ได้ใช้งานอีกต่อไป แต่เมื่อเราพยายามเรียกมันโดยการสร้างวัตถุใหม่มันจะไม่มีความแน่นอนในการโทร ดังนั้นเพื่อความมั่นใจเราจึงสร้างnull
วัตถุc
ที่เห็นได้ชัดว่าไม่มีประโยชน์ในอนาคตดังนั้นเราจึงเห็นการเรียกของวัตถุc
สุดท้าย
ตัวอย่าง
class Car {
int maxspeed;
Car() {
maxspeed = 70;
}
protected void finalize() {
// Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
// Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection
System.out.println("Called finalize method in class Car...");
}
}
class Bike {
int maxspeed;
Bike() {
maxspeed = 50;
}
protected void finalize() {
System.out.println("Called finalize method in class Bike...");
}
}
class Example {
public static void main(String args[]) {
Car c = new Car();
c = null; // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
Bike b = new Bike();
System.gc(); // should clear c, but not b
for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
System.out.print("\t" + b.maxspeed);
if (b.maxspeed > 50) {
System.out.println("Over Speed. Pls slow down.");
}
}
}
}
เอาท์พุต
Called finalize method in class Car...
1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51Over Speed. Pls slow down.
52Over Speed. Pls slow down.
53Over Speed. Pls slow down.
54Over Speed. Pls slow down.
55Over Speed. Pls slow down.
56Over Speed. Pls slow down.
57Over Speed. Pls slow down.
58Over Speed. Pls slow down.
59Over Speed. Pls slow down.
60Over Speed. Pls slow down.
61Over Speed. Pls slow down.
62Over Speed. Pls slow down.
63Over Speed. Pls slow down.
64Over Speed. Pls slow down.
65Over Speed. Pls slow down.
66Over Speed. Pls slow down.
67Over Speed. Pls slow down.
68Over Speed. Pls slow down.
69Over Speed. Pls slow down.
70Over Speed. Pls slow down.
หมายเหตุ - แม้หลังจากพิมพ์ไม่เกิน 70 และหลังจากที่วัตถุ b ไม่ได้ถูกใช้ในโปรแกรมมีความไม่แน่นอนที่ b ถูกล้างหรือไม่ได้รับจาก JVM ตั้งแต่ "วิธีการที่เรียกว่า finalize ใน class Bike ... " ไม่ถูกพิมพ์
System.gc();
ไม่ใช่การรับประกันว่าการรวบรวมขยะจะถูกเรียกใช้จริง
การสรุปจะพิมพ์จำนวนการสร้างชั้นเรียน
protected void finalize() throws Throwable {
System.out.println("Run F" );
if ( checkedOut)
System.out.println("Error: Checked out");
System.out.println("Class Create Count: " + classCreate);
}
หลัก
while ( true) {
Book novel=new Book(true);
//System.out.println(novel.checkedOut);
//Runtime.getRuntime().runFinalization();
novel.checkIn();
new Book(true);
//System.runFinalization();
System.gc();
อย่างที่เห็น. เอาท์เอาท์ต่อไปนี้แสดง gc ที่ถูกเรียกใช้งานครั้งแรกเมื่อจำนวนคลาสคือ 36
C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F
เมื่อต้องต่อสู้กับวิธีการขั้นสุดท้ายเมื่อเร็ว ๆ นี้ (เพื่อกำจัดพูลการเชื่อมต่อระหว่างการทดสอบ) ฉันต้องบอกว่า finalizer ไม่มีหลายสิ่ง การใช้ VisualVM เพื่อสังเกตและใช้การอ้างอิงที่ไม่ดีเพื่อติดตามการโต้ตอบจริงฉันพบว่าสิ่งต่อไปนี้เป็นจริงในสภาพแวดล้อม Java 8 (Oracle JDK, Ubuntu 15):
ความคิดสุดท้าย
ขั้นตอนสุดท้ายไม่น่าเชื่อถือ แต่สามารถใช้ได้เพียงอย่างเดียวเท่านั้น คุณสามารถตรวจสอบให้แน่ใจว่าวัตถุถูกปิดหรือกำจัดก่อนที่จะมีการรวบรวมขยะทำให้สามารถนำไปใช้ในการล้มเหลวได้อย่างปลอดภัยหากวัตถุที่มีชีวิตที่ซับซ้อนมากขึ้นซึ่งเกี่ยวข้องกับการดำเนินการสิ้นสุดชีวิตถูกจัดการอย่างถูกต้อง นั่นคือเหตุผลหนึ่งที่ฉันคิดได้ว่ามันคุ้มค่าที่จะแทนที่มัน
วัตถุมีสิทธิ์ได้รับการรวบรวมขยะหรือ GC หากไม่สามารถเข้าถึงได้จากเธรดสดหรือการอ้างอิงแบบคงที่ใด ๆ ในคำอื่น ๆ ที่คุณสามารถพูดได้ว่าวัตถุนั้นมีสิทธิ์ใช้งานการรวบรวมขยะหากการอ้างอิงทั้งหมดนั้นเป็นโมฆะ การอ้างอิงตามรอบจะไม่นับเป็นการอ้างอิงดังนั้นหากวัตถุ A มีการอ้างอิงของวัตถุ B และวัตถุ B มีการอ้างอิงของวัตถุ A และพวกเขาไม่มีการอ้างอิงสดอื่น ๆ ดังนั้นทั้งวัตถุ A และ B จะมีสิทธิ์สำหรับการรวบรวมขยะ โดยทั่วไปวัตถุจะมีสิทธิ์ใช้งานการรวบรวมขยะใน Java ในกรณีต่อไปนี้:
final
ฟิลด์ของวัตถุซ้ำ ๆ ในระหว่างการคำนวณช้าและจะไม่ใช้วัตถุนั้นหลังจากนั้นวัตถุจะยังคงมีชีวิตอยู่จนกระทั่งรหัสแหล่งสุดท้ายร้องขอเขตข้อมูลหรือ JIT สามารถคัดลอกเขตข้อมูลไปยัง ตัวแปรชั่วคราวแล้วละทิ้งวัตถุก่อนการคำนวณ?
GC.KeepAlive()
ฟังก์ชั่นที่ไม่ทำอะไรเลยนอกจากบังคับให้ GC สมมติว่ามันอาจใช้วัตถุ แต่ฉันรู้ว่าไม่มีฟังก์ชั่นดังกล่าวใน Java เราสามารถใช้volatile
ตัวแปรเพื่อจุดประสงค์นั้นได้ แต่การใช้ตัวแปรเพียงอย่างเดียวเพื่อจุดประสงค์ดังกล่าวจะดูสิ้นเปลือง
FinalizerReference
เพื่อที่จะได้ไม่ต้องใช้วงจร GC เพื่อค้นหาว่าไม่มี การอ้างอิง การซิงโครไนซ์ก็เพียงพอที่จะทำให้แน่ใจว่ามีความสัมพันธ์เกิดขึ้นก่อน ตั้งแต่การสรุปอาจ (จริง ๆ แล้ว) กำลังทำงานในเธรดที่แตกต่างกันมันมักจะจำเป็นอย่างเป็นทางการต่อไป Java 9 กำลังจะเพิ่มReference.reachabilityFence
…
Finalize
จะถูกเรียกได้ก็คือถ้า JIT สร้างรหัสที่ทำเช่นนั้นโดยตรง โดยทั่วไปจะต้องมีการซิงโครไนซ์รหัสสำหรับวัตถุที่คาดว่าจะใช้ในเธรดเดียวเท่านั้นหรือไม่ หากวัตถุดำเนินการบางอย่างที่จำเป็นต้องยกเลิกก่อนที่มันจะถูกยกเลิก (เช่นการเปิดการเชื่อมต่อซ็อกเก็ตและการใช้ประโยชน์จากทรัพยากรในส่วนอื่น ๆ ) การมี finalizer ปิดการเชื่อมต่อในขณะที่รหัสยังคงใช้ซ็อกเก็ต . มันจะเป็นเรื่องปกติสำหรับรหัสการประสานการใช้งาน ...
ไม่รับประกันวิธีการจบขั้นตอนวิธีการนี้เรียกว่าเมื่อวัตถุมีสิทธิ์ได้รับ GC มีหลายสถานการณ์ที่วัตถุอาจไม่ถูกรวบรวมขยะ
บางครั้งเมื่อมันถูกทำลายวัตถุต้องทำการกระทำ ตัวอย่างเช่นหากวัตถุมีทรัพยากรที่ไม่ใช่จาวาเช่นการจัดการไฟล์หรือแบบอักษรคุณสามารถตรวจสอบว่าทรัพยากรเหล่านี้จะถูกปล่อยออกมาก่อนที่จะทำลายวัตถุ ในการจัดการสถานการณ์เช่นนี้จาวามีกลไกที่เรียกว่า "การจบ" คุณสามารถกำหนดการกระทำเฉพาะที่เกิดขึ้นเมื่อวัตถุกำลังจะถูกลบออกจากตัวรวบรวมขยะ ในการเพิ่ม finalizer ให้กับคลาสเพียงกำหนดเมธอดfinalize () เวลาเรียกใช้งาน Java เรียกเมธอดนี้เมื่อใดก็ตามที่มันกำลังจะลบวัตถุของคลาสนั้น ภายในขั้นสุดท้ายวิธีการ ()คุณระบุการกระทำที่จะดำเนินการก่อนที่จะทำลายวัตถุ ตัวรวบรวมขยะถูกค้นหาเป็นระยะ ๆ สำหรับวัตถุที่ไม่ได้อ้างถึงสถานะการทำงานใด ๆ หรือวัตถุอื่น ๆ ที่มีการอ้างอิงทางอ้อม ก่อนที่จะเผยแพร่เนื้อหารันไทม์ของ Java จะเรียกวิธีการfinalize ()บนวัตถุ กระบวนการfinalize ()มีรูปแบบทั่วไปดังต่อไปนี้:
protected void finalize(){
// This is where the finalization code is entered
}
ด้วยคำสำคัญที่ได้รับการป้องกันการเข้าถึงเพื่อจบ ()โดยรหัสนอกชั้นเรียนจะถูกป้องกัน สิ่งสำคัญคือต้องเข้าใจว่าการสรุป ()ถูกเรียกก่อนการรวบรวมขยะ มันไม่ได้ถูกเรียกเมื่อวัตถุออกจากขอบเขตตัวอย่างเช่น หมายความว่าคุณไม่สามารถทราบได้ว่าจะดำเนินการเมื่อใดหรือหากสิ้นสุด () เป็นผลให้โปรแกรมต้องจัดให้มีวิธีการอื่นเพื่อเพิ่มทรัพยากรระบบหรือทรัพยากรอื่น ๆ ที่ใช้โดยวัตถุ คุณไม่ควรพึ่งพา finalize ()สำหรับการทำงานปกติของโปรแกรม
ระดับที่เราแทนที่วิธีจบ
public class TestClass {
public TestClass() {
System.out.println("constructor");
}
public void display() {
System.out.println("display");
}
@Override
public void finalize() {
System.out.println("destructor");
}
}
โอกาสในการสรุปวิธีการที่ถูกเรียก
public class TestGarbageCollection {
public static void main(String[] args) {
while (true) {
TestClass s = new TestClass();
s.display();
System.gc();
}
}
}
เมื่อหน่วยความจำเต็มไปด้วยวัตถุการถ่ายโอนข้อมูล gc จะเรียกวิธีการสรุป
เรียกใช้และดูคอนโซลที่คุณไม่พบวิธีการสิ้นสุดที่ถูกเรียกบ่อยครั้งเมื่อหน่วยความจำได้รับการโอเวอร์โหลดแล้ววิธีการจบจะถูกเรียกว่า
Java อนุญาตให้วัตถุใช้วิธีการที่เรียกว่า finalize () ที่อาจถูกเรียก
finalize () วิธีการได้รับการเรียกว่าถ้าตัวรวบรวมขยะพยายามที่จะรวบรวมวัตถุ
หากตัวรวบรวมขยะไม่ทำงานวิธีจะไม่ถูกเรียกใช้
หากตัวรวบรวมขยะไม่สามารถรวบรวมวัตถุและพยายามเรียกใช้ อีกครั้งวิธีการจะไม่ถูกเรียกใช้ในครั้งที่สอง
ในทางปฏิบัติคุณไม่น่าจะใช้มันในโครงการจริง
เพียงจำไว้ว่ามันอาจไม่ได้รับการเรียกและแน่นอนว่ามันจะไม่ถูกเรียกสองครั้ง กระบวนการ finalize () สามารถเรียกใช้ศูนย์หรือหนึ่งครั้ง
ในโค้ดต่อไปนี้เมธอด finalize () จะไม่สร้างเอาต์พุตเมื่อเรารันตั้งแต่โปรแกรมออกไปก่อนที่จะต้องรันตัวรวบรวมขยะ
finalize()
ถูกเรียกก่อนการรวบรวมขยะ มันไม่ได้ถูกเรียกเมื่อวัตถุออกนอกขอบเขต ซึ่งหมายความว่าคุณไม่สามารถรู้ได้ว่าfinalize()
จะถูกประหารชีวิตเมื่อไรหรือแม้กระทั่ง
ตัวอย่าง:
หากโปรแกรมของคุณสิ้นสุดก่อนที่ตัวรวบรวมขยะจะเกิดขึ้นจากนั้นfinalize()
จะไม่ทำงาน ดังนั้นจึงควรใช้เป็นขั้นตอนการสำรองข้อมูลเพื่อให้แน่ใจว่ามีการจัดการทรัพยากรอื่น ๆ หรือแอปพลิเคชันการใช้งานพิเศษอย่างเหมาะสมไม่ใช่วิธีการที่โปรแกรมของคุณใช้ในการทำงานปกติ
เป็นแหลมออกในhttps://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers ,
ไม่มีเวลาที่แน่นอนที่ต้องดำเนินการขั้นสุดท้ายเนื่องจากเวลาในการดำเนินการขึ้นอยู่กับ Java Virtual Machine (JVM) การรับประกันเพียงอย่างเดียวคือวิธีการขั้นสุดท้ายใด ๆ ที่เรียกใช้งานจะดำเนินการในบางครั้งหลังจากที่วัตถุที่เกี่ยวข้องเข้าไม่ถึง (ตรวจพบในรอบแรกของการรวบรวมขยะ) และบางครั้งก่อนที่ตัวรวบรวมขยะจะเรียกคืนที่เก็บข้อมูลของวัตถุที่เกี่ยวข้อง . การดำเนินการ finalizer ของวัตถุอาจล่าช้าเป็นเวลานานโดยพลการหลังจากที่วัตถุไม่สามารถเข้าถึงได้ ดังนั้นการเรียกใช้ฟังก์ชั่นที่มีความสำคัญต่อเวลาเช่นการจัดการไฟล์ที่ปิดในเมธอด finalize () ของวัตถุจึงเป็นปัญหา
ลองเรียกใช้โปรแกรมนี้เพื่อความเข้าใจที่ดีขึ้น
public class FinalizeTest
{
static {
System.out.println(Runtime.getRuntime().freeMemory());
}
public void run() {
System.out.println("run");
System.out.println(Runtime.getRuntime().freeMemory());
}
protected void finalize() throws Throwable {
System.out.println("finalize");
while(true)
break;
}
public static void main(String[] args) {
for (int i = 0 ; i < 500000 ; i++ ) {
new FinalizeTest().run();
}
}
}