เหตุใดผู้เข้ารอบสุดท้ายจึงมีการลงโทษด้านประสิทธิภาพขั้นรุนแรง?

Java ที่มีประสิทธิภาพ พูดว่า:

มีการลงโทษด้านประสิทธิภาพขั้นรุนแรงสำหรับการใช้โปรแกรมสรุปผล

เหตุใดจึงช้ากว่าในการทำลายวัตถุโดยใช้เครื่องสรุปผล?


comment
คุณอาจชอบบทความนี้ ซึ่งพูดถึงวิธีที่ผู้เข้ารอบสุดท้ายสามารถทำให้ออบเจ็กต์สามารถเข้าถึงได้อีกครั้ง ฯลฯ นอกจากนี้ยังแสดงให้เห็นว่าเหตุใดการเรียบเรียงจึงสามารถกอบกู้วัน (แทนที่จะสืบทอดการใช้งาน) ในบางกรณี: java.sun.com/developer/technicalArticles/javase/finalization   -  person SyntaxT3rr0r    schedule 19.05.2010


คำตอบ (6)


เพราะวิธีการทำงานของคนเก็บขยะ เพื่อประสิทธิภาพ Java GC ส่วนใหญ่ใช้ตัวรวบรวมการคัดลอก โดยที่อ็อบเจ็กต์อายุสั้นจะถูกจัดสรรลงในบล็อกหน่วยความจำ "eden" และเมื่อถึงเวลาที่อ็อบเจ็กต์รุ่นนั้นจะถูกรวบรวม GC เพียงแค่ต้องคัดลอกอ็อบเจ็กต์ที่ ยังคง "มีชีวิต" อยู่ในพื้นที่เก็บข้อมูลถาวร จากนั้นจึงสามารถล้าง (ฟรี) บล็อกหน่วยความจำ "eden" ทั้งหมดได้ในคราวเดียว สิ่งนี้มีประสิทธิภาพเนื่องจากโค้ด Java ส่วนใหญ่จะสร้างอินสแตนซ์ของอ็อบเจ็กต์หลายพันอินสแตนซ์ (แบบพื้นฐานชนิดบรรจุกล่อง อาร์เรย์ชั่วคราว ฯลฯ) โดยมีอายุการใช้งานเพียงไม่กี่วินาที

เมื่อคุณมีผู้เข้ารอบสุดท้ายผสมอยู่ GC จะไม่สามารถล้างรุ่นทั้งหมดพร้อมกันได้ แต่จำเป็นต้องค้นหาออบเจ็กต์ทั้งหมดในรุ่นนั้นที่จำเป็นต้องทำการสรุป และจัดคิวไว้บนเธรดที่ดำเนินการกับโปรแกรมสรุปผลจริง ๆ ในระหว่างนี้ GC ไม่สามารถทำความสะอาดวัตถุได้อย่างมีประสิทธิภาพ ดังนั้นจึงต้องรักษาพวกมันให้มีชีวิตอยู่นานกว่าที่ควรจะเป็น หรือต้องชะลอการรวบรวมวัตถุอื่น ๆ หรือทั้งสองอย่าง นอกจากนี้คุณยังมีเวลารอตามอำเภอใจในการดำเนินการรอบสุดท้ายจริงๆ

ปัจจัยทั้งหมดเหล่านี้รวมกันทำให้เกิดการลงโทษรันไทม์ที่สำคัญ ซึ่งเป็นเหตุผลว่าทำไมการสรุปแบบกำหนด (โดยใช้เมธอด close() หรือที่คล้ายกันเพื่อสรุปสถานะของออบเจ็กต์อย่างชัดเจน) จึงเป็นที่ต้องการ

person Daniel Pryden    schedule 18.05.2010
comment
แน่นอนว่าสิ่งนี้มุ่งเน้นไปที่ประเด็นปัญหากับนักสะสมรุ่นต่อรุ่น กลยุทธ์ GC อื่นๆ มีปัญหาที่แตกต่างกัน แต่พวกเขาทั้งหมดเดือดลงไปที่ GC จำเป็นต้องทำงานพิเศษรวมถึงการผ่านวัตถุอย่างน้อยสองครั้งเพื่อปลดปล่อยมัน รายการหนึ่งเพื่อเพิ่มลงในคิวสรุป และอีกรายการหนึ่งให้ว่างจริง ๆ หลังจากการสรุปผล - person Lawrence Dol; 19.05.2010
comment
ฉันจะคิดถูกไหมว่าคลาส Java API ที่ใช้กันทั่วไปหลายคลาสมีตัวสรุปเพื่อให้ทรัพยากร O/S ฟรี ฉันกำลังคิดถึง FileOutputStream ดังนั้นจึงไม่น่าจะเป็นไปได้ที่ตัวสรุปสำหรับบางอ็อบเจ็กต์จะทำให้ GC ของอ็อบเจ็กต์ที่ไม่ได้ใช้ตัวสรุปนั้นล่าช้า เนื่องจากโปรแกรมส่วนใหญ่จะได้รับผลกระทบ - person Raedwald; 01.08.2014
comment
@Raedwald: ใช่แล้ว ตัวอย่างเช่น การใช้งาน OpenJDK ของ FileOutputStream มีตัวสรุป ซึ่งคุณสามารถดูได้โดยดูที่แหล่งที่มาของ OpenJDK (แต่ฉันไม่พบสิ่งใดที่ต้องการการใช้งานไลบรารีมาตรฐานเพื่อใช้ตัวสรุป) ดังนั้นในทางปฏิบัติ ออบเจ็กต์ที่มีสิทธิ์สำหรับ GC แต่ยังคงรอการสรุปจะถูกเลื่อนระดับเป็น รุ่นเก่าต่อไป (พื้นที่ผู้รอดชีวิตหรือดำรงตำแหน่ง) ในขณะที่ผู้เข้ารอบสุดท้ายอยู่ในคิวให้ทำงาน แต่ความทรงจำที่แท้จริงจะไม่ถูกเรียกคืนจนกว่าจะรวบรวมคนรุ่นเก่าต่อไป - person Daniel Pryden; 01.08.2014
comment
สมมติว่าวัตถุที่มีทั้งการใช้งาน close() และ finalize() โอเวอร์เฮดนี้จะเกิดขึ้นด้วยหรือไม่หากเราเรียก close() อย่างชัดเจน - person Gerardo Cauich; 26.06.2021

เมื่อประสบปัญหาดังกล่าวจริง ๆ แล้ว:

ใน Sun HotSpot JVM ตัวสรุปจะถูกประมวลผลบนเธรดที่ได้รับลำดับความสำคัญคงที่และต่ำ ในแอปพลิเคชันที่มีโหลดสูง เป็นเรื่องง่ายที่จะสร้างออบเจ็กต์ที่ต้องการการสรุปผลได้เร็วกว่าที่เธรดการสรุปผลที่มีลำดับความสำคัญต่ำสามารถประมวลผลได้ ในขณะเดียวกัน พื้นที่บนฮีปที่ใช้โดยออบเจ็กต์ที่รอการสรุปจะไม่พร้อมใช้งานสำหรับการใช้งานอื่นๆ ในที่สุด แอปพลิเคชันของคุณอาจใช้เวลาทั้งหมดไปกับการรวบรวมขยะ เนื่องจากหน่วยความจำที่มีอยู่ทั้งหมดถูกใช้โดยอ็อบเจ็กต์ที่รอการสรุป

แน่นอนว่านี่คือ นอกเหนือจากเหตุผลอื่นๆ มากมายที่จะไม่ใช้ตัวสรุปที่อธิบายไว้ใน Effective Java

person Sbodd    schedule 18.05.2010

ฉันเพิ่งหยิบสำเนา Effective Java ขึ้นมาจากโต๊ะเพื่อดูว่าเขาหมายถึงอะไร

หากคุณอ่านบทที่ 2 ตอนที่ 6 เขาจะอธิบายรายละเอียดที่ดีเกี่ยวกับการแสดงยอดนิยมต่างๆ

You can't know when the finalizer will run, or even if it will at all. Because those resources may never be claimed, you will have to run with fewer resources.

ฉันอยากจะแนะนำให้อ่านเนื้อหาทั้งหมด - มันอธิบายสิ่งต่าง ๆ ได้ดีกว่าที่ฉันจะสามารถนกแก้วได้ที่นี่

person corsiKa    schedule 18.05.2010

หากคุณอ่านเอกสารประกอบของ Finalize() อย่างใกล้ชิด คุณจะสังเกตเห็นว่า Finalizer เปิดใช้งานออบเจ็กต์เพื่อป้องกันไม่ให้ GC รวบรวม

หากไม่มีตัวปิดท้าย วัตถุก็สามารถลบออกได้และไม่ต้องการการดูแลอีกต่อไป แต่หากมีตัวสรุป จะต้องตรวจสอบในภายหลัง หากวัตถุนั้นไม่ "มองเห็น" ได้อีก

โดยไม่ทราบแน่ชัดว่าการรวบรวมขยะ Java ปัจจุบันถูกนำไปใช้อย่างไร (อันที่จริงแล้ว เนื่องจากมีการใช้งาน Java ที่แตกต่างกันออกไป จึงมี GC ที่แตกต่างกันด้วย) คุณสามารถสรุปได้ว่า GC จะต้องทำงานเพิ่มเติมบางอย่างหากวัตถุมีตัวสรุป เนื่องจาก ของคุณสมบัตินี้

person Simon Lehmann    schedule 18.05.2010
comment
อันที่จริง หน้านี้ยังกล่าวถึงด้วยว่า JVM ปฏิบัติต่อออบเจ็กต์ที่มีตัวสรุปที่ไม่ไม่สำคัญแตกต่างกัน: fasterj.com/ บทความ/finalizer2.shtml - person Gerardo Cauich; 26.06.2021

ความคิดของฉันคือ: Java เป็นภาษาที่รวบรวมขยะซึ่งจัดสรรหน่วยความจำตามอัลกอริธึมภายในของตัวเอง บ่อยครั้งที่ GC จะสแกนฮีป กำหนดว่าออบเจ็กต์ใดจะไม่ถูกอ้างอิงอีกต่อไป และยกเลิกการจัดสรรหน่วยความจำ Finalizer ขัดจังหวะสิ่งนี้และบังคับให้มีการจัดสรรหน่วยความจำนอกวงจร GC ซึ่งอาจทำให้เกิดความไร้ประสิทธิภาพ ฉันคิดว่าแนวทางปฏิบัติที่ดีที่สุดคือการใช้ตัวสรุปเมื่อจำเป็นเท่านั้น เช่น การเพิ่มตัวจัดการไฟล์หรือการปิดการเชื่อมต่อฐานข้อมูลซึ่งควรทำตามที่กำหนดไว้

person Jeremy    schedule 18.05.2010
comment
มันบังคับจริงๆหรือแค่แนะนำ? - person corsiKa; 18.05.2010
comment
ส่วนใหญ่ถูกต้อง แต่ผู้เข้ารอบสุดท้ายจะไม่ทำให้เกิดการจัดสรรหน่วยความจำนอกวงจร GC ในทางกลับกัน หาก GC พิจารณาว่าจำเป็นต้องทำการสรุปออบเจ็กต์ มันจะฟื้นคืนชีพและป้องกันไม่ให้มีการรวบรวมออบเจ็กต์จนกว่า Finalizer จะถูกดำเนินการ แต่อาจใช้เวลาสักครู่ เนื่องจากตัวสรุป (IIRC) จะไม่ทำงานจนกว่าจะรวบรวมรุ่นที่ดำรงตำแหน่งในครั้งถัดไป - person Daniel Pryden; 18.05.2010
comment
ฉันคิดว่าแนวทางปฏิบัติที่ดีที่สุดคือการใช้ตัวสรุปสุดท้ายเมื่อจำเป็นจริงๆ เท่านั้น เช่น การเพิ่มตัวจัดการไฟล์หรือการปิดการเชื่อมต่อฐานข้อมูล: โปรดทราบว่านี่คือจุดที่ตัวสรุป ไม่ เหมาะสมอย่างชัดเจน เนื่องจากตัวสรุปอาจทำงานล่าช้าโดยพลการหรือไม่ที่ ทั้งหมด. - person sleske; 04.10.2010

เหตุผลหนึ่งที่ฉันคิดได้ก็คือการล้างหน่วยความจำอย่างชัดเจนนั้นไม่จำเป็นหากทรัพยากรของคุณคือ Java Objects ทั้งหมด ไม่ใช่โค้ดเนทีฟ

person Amir Afghani    schedule 18.05.2010