.NET events cause uncontrolled memory usage
Suppose we have one Windows Form with a SimpleButton1. The following code results in an uncontrolled amount of memory usage. What am I doing wrong?
I understand that on each iteration of the for loop, the GC cleans up any TestClass objects and also takes care of any related events as there are no handlers on any of the events
Public Class Form1
Private Sub SimpleButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SimpleButton1.Click
For i = 1 To 1000000
Dim test1 As New TestClass
Next
End Sub
End Class
Public Class TestClass
Private Event TestEvent(ByVal sender As Object)
End Class
Note that I tried to implement IDisposable and call test1.Dispose () at the end of each iteration of the For loop, but I suspect I don't have the correct resources.
* ANSWERED: There was no problem in the code and it ran as expected. The problem was that I was running it in debug mode and the overhead generated was causing a lot of memory usage. See discussion below.
source to share
If you are working in Debug, VisualStudio will generate additional edit and continue code (_EncList) even if you are not under the debugger.
Be sure to compile and run during the build process like "Release". Yes, it makes it difficult to debug memory problems when they behave differently, but it is not the most difficult task to track down memory problems.
source to share
Which you are not showing here, and I suspect the problem is that you have a TestEvent event in your TestClass, and while you are probably adding handlers to the TestEvent, you are probably not removing them. By not removing them, you are telling the GC to collect neither the TestClass nor the handler class.
source to share
This code, as you showed it, will not leak. The garbage collector will eventually take care of the classes you created.
However, if you have an Observable class and an Observer class, Observer will call Observable.Event += Observer.EventHandler;
. Thus, the Observable now has a reference to the Observer. If you don't call Observable.Event -= Observer.EventHandler
, then this link remains.
The problem with this happens when you think that nobody has a reference to the Observer, but the Observable has a longer lifespan. Although the Observable has a link to the Observer, there is no code that knows to remove the link, unless it clears all of the handlers ( this.Event = null
).
This is essentially a memory leak!
There are several ways to get around this:
- Call - = before dropping the Observer. Perhaps in Dispose ()
- Use Weak Events
- Consider another event pattern like Event Aggregator
source to share
-
GC does not execute spring in action at every iteration, it will wait for the right moment and mass these objects in bulk.
-
TestEvent shouldn't block GC collection, but if TestClass instances subscribe to an event on another object, this will keep them alive. No automatic cleaning.
-
How do you define "leads to uncontrolled memory usage". Measuring memory usage is trickier than it sounds. Hopefully this is not based on TaskManager.
source to share