WinForms issue with Windows 10, version 1803

One of our customers has reported to us a issue with our WinForms controls, one that is related to a GDI resource leak. In their case, it caused an application crash – their system has a limit on how many GDI objects can be allocated.

Upon investigation by the team it turns out that the leak is related to Windows 10 version 1803 (also known as the Windows 10 April 2018 Update), or later.

We devised a really simple test to reproduce the issue:

private void button1_Click(object sender, EventArgs e) {
  for(int x = 0; x < 100; x++) {
    using(var f = new Form() { ShowInTaskbar = false }) {
      f.Show();
    }
  }
}

This particular nasty piece of code – I don’t advise you use it in production! – will “leak” 300 GDI objects, since each form created with ShowInTaskbar = false will leak 3 GDI objects. It’s a very common scenario to have such an option turned on (all popups, tooltips, menus, drag-n-drops, alerts, etc. are examples of such forms), and if the application has a relatively complex UI and is run continuously, sooner or later it will crash or freeze.

We have already devised a workaround for this issue. Needless to say, some rigorous testing is currently being done to make sure we don’t break anything else. We shall be updating our WinForms components from v17.1 or later to include it.

We are contacting Microsoft to see if they aware of the issue, and trying to determine if they have any timeframe for a proper fix.

 

UPDATE (3-Aug-2018)

It seems I could have been a little more forthcoming and descriptive in my original post, so let me expand a little more. I will also stress that this issue is not specific to DevExpress, but is an “artifact” of the .NET Framework.

Basically the only applications that are really affected are those which use a dynamic UI – that is, apps that create and destroy new forms rather than reuse them (so for example, an invoice/order form where when you create the data entry UI every time the user wishes to enter a new record) – or an app which creates, say, lot of visual notifications.

Since it affects all forms which have ShowInTaskbar = false,  it does apply to almost every one of our UI controls – but I hasten to add that this setting is common practice, and not something we invented here at DevExpress.

Every “dropdown” window is created on the fly in a similar fashion. Examples include: combobox edits, popup menus, lookup edits, backstage menu, filter popups, alert windows, tooltips, drag & drop features, and so on. When you use such editors/controls in a form, a GDI object leak will occur. Now, as it happens, we coded things in such a way to reuse most of these window objects, so if you open the same popup 10 times, say, a leak will occur only once. But if you created a form that contains a combobox 10 times and each time that form is used the user opens the combobox, the app will have leaked 30 GDI handles.

I’d have to say though, since Windows 10 does have a relatively high GDI object limit, the average app would need to be running continuously for a pretty long time before it suffers from a lack of GDI resources.

You can monitor GDI object usage for your apps yourselves: open the Windows Task Manager, go to the Details pane, right-click on the column header row, and choose Select columns. One of the columns is called GDI objects. Select that check box and click OK.

Task Manager GDI object count

Start up your app and watch that new column as you use the UI, especially those forms with examples of those “dropdown” controls I mentioned.

27 comment(s)

Remember in the 90's MS programs would eat up the very small resource memory back then.

I remember testing Word, loading it multiple times and after awhile would have to reboot just to use the PC. This 1803 version takes me back! ;)

2 August, 2018

Wait, can you please be more specific on how this affects our applications?  It's not just when ShowInTaskbar = True, is it?

2 August, 2018

Is there a link to the ticket for this, as i think the program i am working on may suffer from this issue?

2 August, 2018

Hi, do we know if this is purely Windows 10? are Windows Server 2012/2016 affected?

3 August, 2018

You know, we have been getting reports of our program suddenly freezing or crashing when left open overnight and similar problems.  This fix is badly needed.  What is the ETA and PLEASE be more specific about the problem.

3 August, 2018

I'm not sure if that is related but on Win 10 1803 I have black screen if main thread is busy even with overlay form.

Win 7 doesn't have this problem.

3 August, 2018

Tony,

Here is the issue link: www.devexpress.com/.../alertcontrol-gdi-objects-leak-after-alertforms-dispose-in-windows-10-1803

According to the ticket, a hotfix is already in preparation with a fix.

3 August, 2018

They put out a .NET update recently that caused a crash in WPF applications (something to do with font familys). I can't express enough how extremely frustrated I and quite a few other people are with their constant updates and poor QA, so please do us a favor, Julian, and pass that on while you're talking to them.

3 August, 2018

First: thanks to everyone who has commented here and provided valuable feedback.

Second: it seems my description wasn't quite as detailed and explanatory as it should have been, so I've added more information in an "UPDATE" section at the end of the post.

3 August, 2018

This problem affects our program a good deal actually.  Looking forward to the fix... this will help us with a lot of recent complaints I think.

3 August, 2018

Looking for the # of GDI-Objects i found knowledge.ni.com/KnowledgeArticleDetails

The number is 10000. and can  be changed in the registry

4 August, 2018

to get the actual number of gdi-objects in code

[DllImport("User32")]

private extern static int GetGuiResources(IntPtr hProcess, int uiFlags);

using (var process = Process.GetCurrentProcess())

{

 var gdiHandles = GetGuiResources(process.Handle, 0);

}

4 August, 2018

Hi

I believe that this is the issue i have in my program. there are 100s of forms within it, and it crashes more often for certain users and other. in retrospection, it fits the pattern that the users that it locks on more often, are the ones that open and close forms often.

On the ticket link that was supplied, there is a hot fix being prepared, is this hotfix to fix the GDI issue? or is it to fix something else in the ticket? (as the original ticket is private, so can't tell the scope of the fix).

4 August, 2018

The Limit of 10.000 per process and 16K Ressources for the whole system (for each display session) is as old as windows exists.

If one process creates 10.000 GDI's, than all other processes must share the rest.

Shure, you can change the limit to higher value, but the global memory GDI-Table is limited to 16K Entries. It exists many GDIObjects like Pens, Brushes, Regions, Fonts, Icons, Bitmaps. I have test it in older windows versions, to extend the GDI-Table to 32K, but that is not used from windows.

So it is always very importent to destroy GDI's when they are not used anymore. The creation of GDI's is fast enough, so you must not hold this in cache, because in cache you hold also a systemwide resource.

Also the provided DLL-Functions does not give exact results.

In an old application i have wrote a gdi-killfunction for all not used GDI's that ar not kill at form unload and also does kill all gdi's that are not used in "hidden" forms. So i could save 1000s of GDIs to run the application longer.

5 August, 2018

Tony,

Yes, we have managed to find a workaround and fix this issue at the level of our components. This means that our components shouldn't be affected by this problem once you install the fix (or an official update once it is available).

6 August, 2018

Any details on which version of your components/.NET Framework is affected by this? The reason I ask, is if it's wide ranging and includes the version our latest branch of our software is on, this could have major implications for us.

6 August, 2018

We saw a similar problem when using a different vendors controls.  In our case, we could free the GDI and User resources by calling the form's Dispose method whenever a form was closing.  I seem to recall that we only noticed the problem was related to forms and not other controls, but I'm not positive about that.

6 August, 2018

Is the thread link above THE one where the hotfix will be posted?  Can you guys PLEASE tell us when and where this fix will be posted?

6 August, 2018

Mark:  Every version of .net framework is affected when running on Windows 10 1803 (April 2018)

Steve: It's different issue and Dispose is not going to resolve it (as you see in code snippet)

6 August, 2018

Your update mentions ShowInToolbox = false - I think that should be ShowInTaskBar.

7 August, 2018

wolfgang hauer: Thanks for that code snippet. I'll use that.

7 August, 2018

Simon: Oops, too enthusiastic (or I was conflating a couple of things). Fixed.

Cheers, Julian

7 August, 2018
12 August, 2018

According to this article, 1803 is Win 10, build 17134.  

docs.microsoft.com/.../windows-10-build-17134

Is it just best to avoid this version until a fix from MS is release?

14 August, 2018

@Steve: Er, well, to be honest, that's just not feasible. It's installed by Windows Update (mine, on this machine, was installed on May 1), so I would hazard a guess that it's on the majority of our customers' customers' machines already.

Cheers, Julian

14 August, 2018

FWIW

In the article I mention above the poster states that

"This leak only occurs when no owner (or a null owner) is passed to Show/ShowDialog AND ShowInTaskbar is set to false for the form."

Here is what MSDN states about ShowDialog

"This version of the ShowDialog method does not specify a form or control as its owner. When this version is called, the currently active window is made the owner of the dialog box. If you want to specify a specific owner, use the other version of this method."

15 August, 2018

This problem is as old as windows!

The limit of 16K GDI-Objects per Session (Dialog, Taskscheduler, Terminalserver) and 10,000 per process is indepent of the windows and Bit-version. The GDI-Handle is always a 32-Bit-Value.

I didnt find any documentation, that this has been changed.

The leek is, shure, a problem of each application.

You can force this problem with gdi-resources, if you hold (cache) GDI-Ressources for reuse also.

Each bitmap, which is created at runtime (loaded) takes also a gdi-resource!

So if the bitmap is drawn to the context it should be deleted.

In case of Dispose of the form, your bitmap will not be deleted, because the context of the form does not hold a reference to it.

You can select the bitmap to the context, but this will set the background of the context. In case of dispose, the bitmap will be deleted, if it is the last use.

Shure, you can cache GDI's by your own, but it has only advantage, if you use these objects very very often.

If you cache 100 and more gallery icons you need as many gdi's.

Simple GDI's like Pens, Brushes, Fonts are core objects and will be created very fast. GDI's like Icons, Bitmaps should be better stored in an rasterd bitmap, so you have multiple icons in one bitmap and draw each one with its relative coordinates.

What i dont understand is, that microsoft don't create a dynamic gdi-table for each process, so each process can have 32K GDI's.

docs.microsoft.com/.../ns-wingdi-taghandletable

The Handle contains the ProcessId and the 16-Bit original Handle, thats why only 32K (+/- 16767 except 0)!

4 September, 2018

Please login or register to post comments.