.NET: Leak in Windows Forms

Consider this Windows Forms code:

int i, j;
for (i = 0; i < 150; i++)
{
    for (j = 0; j < 200; j++)
    {
        this.Controls.Add(new Button());
    }
    this.Text = String.Format("i={0}", i);
    this.Controls.Clear();
}

You might need to change 150 and 200 to larger values for your system, but this code should eventually crash saying something like "Cannot create window handle". This is because the Clear() call does not instanltly release the Buttons. The GC should eventually do it, but he fails to do it on time.

What's the cause for this? First of all, consider that Windows Forms is built on top of the Win32 API, so there is a message pump behind. Second, consider that in Win32, a window handle or any other graphic resource can only be destroyed by the thread who created it. Therefore, when the GC wants to destroy a Button, he must dispatch the call to the GUI thread. And he does it via the message pump. Therefore, it the pumps blocks for some reason, the controls are not freed.

Therefore, we have two choices: make sure the pump does not block, or unblock it forcefully. The second choice is the easiest, it can be done this way:

int i, j;
for (i = 0; i < 150; i++)
{
    for (j = 0; j < 200; j++)
    {
        this.Controls.Add(new Button());
    }
    this.Text = String.Format("i={0}", i);
    this.Controls.Clear();
    Application.DoEvents();
}

As expected, this has a downside: Application.DoEvents() is quite a costly call and should be used in moderation.

And say... What if we do the same using WPF, which doesn't use Win32 and is supposed to be way better?

for (var i = 0; i < 150; i++)
{
   for (var j = 0; j < 200; j++)
   {
        mGrid.Children.Add(new Button());
   }
   mGrid.Children.Clear();
}

This never hangs! So if you can, better move on to WPF. Doing so should be quite easy if your GUI is well isolated from your bussiness logic.

Reference: Forum post

Comments

Popular posts from this blog

VB.NET: Raise base class events from a derived class

Apache Kafka - I - High level architecture and concepts

Upgrading Lodash from 3.x to 4.x