When does these unsubscribed events memory leak occurs? Should I write destructor or implement IDisposable to unsubscribe an event?
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
- How to know full paths to DLL's from .csproj f
Let's say that A references B. Furthermore, say you think you're done with B and expect it to be garbage collected.
Now, if A is reachable[1], B won't be garbage collected, despite the fact that "you're done with it". This is, in all essence, a memory leak[2]
If B subscribes to an event in A, then we have the same situation: A has a reference to B via the event handler delegate.
So, when is this a problem? Only when the referencing object is reachable, as mentioned above. In this case, there can be a leak when a Foo instance isn't used any longer:
The reason why there can be a leak is that the Bar instance passed in the constructor can have a longer lifetime than the Foo instance using it. The subscribed event handler can then keep the Foo alive.
In this case you need to provide a way to unsubscribe from the event to not get a memory leak. One way of doing that is by letting Foo implement IDisposable. The upside of that is that it clearly signals to the class consumer that he need to call Dispose() when done. Another way is to have separate Subscribe() and Unsubscribe() methods, but that doesn't convey the type's expectations - they are too optional to call and introduce a temporal coupling.
My recommendation is:
Or alternatively:
On the other hand, when the referencing object isn't reachable, there can't be a leak:
In this case any Foo instance will always outlive its composed Bar instance. When a Foo is unreachable, so will its Bar be. The subscribed event handler cannot keep the Foo alive here. The downside of this is that if Bar is a dependency in need of being mocked in unit testing scenarios, it can't (in any clean way) be explicitly instantiated by the consumer, but needs to be injected.
[1] http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
[2] http://en.wikipedia.org/wiki/Memory_leak
An event handler contains a strong reference to the object that declares the handler (in the delegate's
Target
property).Until the event handler is removed (or until the object owning the event is no longer referenced anywhere), the object containing the handler will not be collected.
You can fix this by removing the handler when you no longer need it (perhaps in
Dispose()
).A finalizer cannot help, because the finalizer would only run after it can be collected.