I have a parent object that has a reference to a child object and additionally the parent has an event handler that listens to an event of the child object.
If all references to the parent object will be released, will the memory used through the parent and the child be freed through GC? (Assuming that no more references neither to the child nor to the parent exist).
class ParentClass {
ChildClass _childClass;
public ParentClass(ChildClass childClass) {
_childClass = childClass;
childClass.SomeEvent += ChildClass_SomeEvent;
}
void ChildClass_SomeEvent(object sender, SomeEventArgs e) {
}
}
Please note, I'm aware that GC does not react immediately. My question is not if the memory is freed immediatly after 开发者_高级运维releasing the parent object. My question is, if the memory is released anyhow.
Update
For me it seems that the answer is a clear yes, GC is able to resolve this circular reference. But for all who read this post and have a similar question, take care to not leave event-registration open. It's only a special example in which the registration is no problem. In other cases, event-registrations may cause serious memory leaks.
A very good resource covering this question was provided by vilx: http://www.interact-sw.co.uk/iangblog/2004/07/07/circulareventrefs
Yes. .NET GC handles circular references without problems (assuming that you are not using unmanaged resources or you implement IDisposable if you do).
Well, if nothing else was using the same instance of _childClass
, yes it would be collected. However, I'm not sure what the implications are of you not detaching the event handler - event handlers left registered are a source of un-GC-able memory leaks in .NET applications - yours is an interesting take on the problem.
Update: turns out my understanding of the memory leak source was backwards. If class A subscribes to class B but does not unsubscribe, then A will only be collected when B is collected (because B's subscription list is keeping A alive). For long lived event sources, this can be a problem for subscribers.
The problem occurs in all object life-spans, but in reality, if B is just as short-lived as A, the leak is not noticed and not usually a problem.
Update 2: in the case of the OP's example, child is the source and parent is the subscriber - the GC can handle this situation - so long as child is not referenced outside of the parent, meaning child is not elligible for collection (this will keep the parent alive).
When there are no more strong references to a particular object on the heap (i.e. reference count has gone to zero), the GC is indeed scheduled to release memory for the object. It doesn't matter where or how these references are defined; they are tracked by the GC and handled accordingly.
Worth noting however: the GC is very non-deterministic way by nature (it runs on a separate thread, for a start), and may not get around to destroying the object in memory for some time. "Some time" is usually almost instantaneous, except in unusual cases where the processor is too busy and/or a lot of memory is being freed up at once.
childClass.SomeEvent += ChildClass_SomeEvent;
This code means, that child has reference to parent. This is circular reference, GC can handle this. Unsubscribed event can be dangerous in another case. Let's say that instead of childClass you have some independent instance:
anotherClass.SomeEvent += AnotherClass_SomeEvent;
Now, when you think that ParentClass may be collected, it actually remains alive, if anotherClass still exists and event subscription is not canceled. Only when anotherClass is collected, ParentClass may be collected as well.
精彩评论