ตัวจัดการเหตุการณ์หยุดการรวบรวมขยะหรือไม่?


183

หากฉันมีรหัสต่อไปนี้:

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass = null;

pClass จะถูกรวบรวมขยะหรือไม่ หรือมันจะแขวนรอบยังคงยิงเหตุการณ์เมื่อใดก็ตามที่พวกเขาเกิดขึ้น? ฉันจะต้องทำสิ่งต่อไปนี้เพื่ออนุญาตการเก็บขยะหรือไม่

MyClass pClass = new MyClass();
pClass.MyEvent += MyFunction;
pClass.MyEvent -= MyFunction;
pClass = null;

11
ฉันจะแนะนำผู้อ่านที่สนใจในคำถามนี้อย่างไม่แน่นอนว่ามันอาจคุ้มค่าที่จะทำความคุ้นเคยกับเหตุการณ์ที่มีน้ำหนักเบา / รูปแบบเหตุการณ์ที่ไม่ดีซึ่งไม่ได้ป้องกันการเกิดขยะขึ้น bootstrap SO ที่ดีในหัวข้อนี้คือstackoverflow.com/questions/185931/…
fostandy

20
Note for posterity: การตั้งค่าการอ้างอิงเป็น null จะทำให้ตัวรวบรวมขยะล่าช้าโดยการขยายขอบเขตของการอ้างอิงหนึ่งบรรทัด .NET ไม่ใช่ VB6
John Saunders

คำตอบ:


207

สำหรับคำถามเฉพาะ "จะ pClass เป็นขยะที่รวบรวม": การสมัครสมาชิกกิจกรรมไม่มีผลต่อการรวบรวม pClass (ในฐานะผู้เผยแพร่)

สำหรับ GC โดยทั่วไป (โดยเฉพาะเป้าหมาย): ขึ้นอยู่กับว่า MyFunction เป็นแบบสแตติกหรืออิงตามอินสแตนซ์

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

โปรดทราบว่านี่เป็นทางเดียว เช่นถ้าเรามี:

publisher.SomeEvent += target.SomeHandler;

จากนั้น "ผู้เผยแพร่" จะทำให้ "เป้าหมาย" ยังมีชีวิตอยู่ แต่ "เป้าหมาย" จะไม่ทำให้ "ผู้เผยแพร่" ยังมีชีวิตอยู่

ดังนั้นไม่: หาก pClass จะถูกรวบรวมต่อไปไม่จำเป็นต้องยกเลิกการสมัครรับฟัง แต่ถ้าได้รับการ pClass ยาวอาศัยอยู่ (นานกว่าอินสแตนซ์ที่มี MyFunction) แล้ว pClass สามารถเก็บตัวอย่างที่มีชีวิตอยู่จึงจะมีความจำเป็นต้องยกเลิกการเป็นสมาชิกถ้าคุณต้องการเป้าหมายที่จะเก็บ

อย่างไรก็ตามเหตุการณ์แบบคงที่ด้วยเหตุผลนี้มีอันตรายมากเมื่อใช้กับตัวจัดการตามอินสแตนซ์


6
ดีถ้าคำถามคือ "จะ pClass เป็นขยะที่เก็บรวบรวม" แล้วคำตอบ "มันขึ้นอยู่กับว่า ... " ไม่ถูกต้องจริง มันไม่ได้ขึ้นอยู่กับอะไรเลยขณะที่มาร์คเองจดบันทึกลงไปอีก
Tor Haugen

@Tor - ยุติธรรมเพียงพอ - ฉันจะอธิบาย
Marc Gravell

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

คำตอบที่ยอดเยี่ยมเพราะมันตอบคำถามอีกครึ่งหนึ่ง (ที่ไม่ได้ถาม): ผู้เผยแพร่จะหยุดไม่ให้ผู้สมัครเป็น GC'd
Bob Sammers

ใช่และอย่างที่ @BobSammers พูดว่าอาจเป็นปัญหาจริง ๆ ถ้าอินสแตนซ์ที่มีชีวิตสั้นเช่น Form / Window กำลังสมัครใช้บริการแบบยาวเช่น Singleton ที่ให้ข้อมูลเช่น: Singleton เก็บข้อมูลอ้างอิงไว้แล้ว และวัตถุต่าง ๆ ก็ถูกเก็บไว้ในความทรงจำแม้ว่าเราคิดว่าพวกมันไม่ได้บรรทุก! ดังนั้นโปรดระมัดระวังเมื่อใช้กิจกรรม เราใช้งานกิจกรรมซอฟต์แวร์ขนาดใหญ่ในทางที่ผิดและเป็นการยากที่จะแก้ไขในภายหลัง
Elo

9

ใช่ pClass จะถูกเก็บรวบรวมขยะ การสมัครสมาชิกเหตุการณ์ไม่ได้หมายความว่าการอ้างอิงใด ๆ มีอยู่สำหรับ pClass

ไม่คุณจะไม่ต้องถอด handler เพื่อให้ pClass ถูกรวบรวมขยะ


8

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

หากคุณไม่แน่ใจว่ามีบางสิ่งที่จะถูกรวบรวมถามตัวเองด้วยคำถามต่อไปนี้: ยังมีการอ้างอิงอยู่หรือไม่? ตัวจัดการเหตุการณ์ถูกอ้างอิงโดยอินสแตนซ์ของวัตถุไม่ใช่วิธีอื่น


0

pClassจะถูกเก็บขยะ แต่ถ้าข้อมูลโค้ดข้างต้นอยู่ในระดับอีกตัวอย่างของการเรียนที่อาจจะไม่ถูกล้างถ้าคุณไม่ได้กำหนดที่จะpClassnull

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.