Solved

CreateCompatibleDC memory leak?

Posted on 2009-07-15
13
1,302 Views
Last Modified: 2013-11-20
I created a simple VC++ 6.0 MFC application, one dialog as a test. The attached snippet is my OnOK() handler.  All it does is loop indefinitely calling CreateCompatibleDC() and then DeleteDC.

When I first run the app and check it out in Task Manager, I see it consuming 8,308k of memory. This holds steady (it's not doing anything.) I then click the OK button, and the attached snippet runs. Memory usage grows very rapidly.

Why is this? Does something else need to be done to delete the device context?



void CSystemHealthDlg::OnOK() 

{

	CDC memDC;

	while (1==1)

	{

		memDC.CreateCompatibleDC(NULL);

		memDC.DeleteDC();

	}

	

	CDialog::OnOK();

}

Open in new window

0
Comment
Question by:PMH4514
  • 7
  • 5
13 Comments
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 24864184
The code is correct.
Actually it can look this way:
HDC hDC = ::CreateCompatibleDC(NULL);
::DeleteDC(hDC);
I think HDC takes about 10 bytes in the global memory - I'm not sure, I don't remember exactly. So the memory usage you see should be explained somehow else but not with the HDC and these 2 lines - Create, Delete.
Actually you can find many complains about the CDC, but.. in real people just forget there something selected and so, DeleteDC does not release the resource. And this is the leak. But this is the GDI leak.
0
 
LVL 30

Expert Comment

by:Zoppo
ID: 24867511
I agree with pgnatyuk - the code snippet you posted shouldn't leak - I even tested in a test application.

Is this all of the code which you use? Or does something happen in between creation and deletion of the DC?

ZOPPO
0
 

Author Comment

by:PMH4514
ID: 24868786
Hi All -

Zoppo - you actually created the same test app and it doesn't leak? Weird.. There is literally nothing else in my test app. I created a new MFC project, changed settings to UNICODE, added that snippet and ran it.

0
 

Author Comment

by:PMH4514
ID: 24868826
I just tried using pgnatyuks version instead (using HDC) and it does not appear to leak. His gives a handle to a DC, whereas mine returned CDC. There would be subsequent code of course, selecting GDI objects into it.. whereas I would do memDC.SelectObject(..) what would I do with the handle?
0
 

Author Comment

by:PMH4514
ID: 24869087
Further followup (sorry for 3 posts in a row) - I just created a new version of my test app leaving it as _MBCS and not _UNICODE, and it does NOT leak.

So, why would UNICODE cause this to leak? And is there a workaround?
0
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 24870596
I'm afraid the leak is already here "I created a new MFC project". BoundChecker always complains about the MFC.
You can set breakpoint in your code on memDC.CreateCompatibleDC(NULL); and you will see the same code I posted, plus usual MFC stuff.
CDC is just a trivial wrapper on HDC. Eveything is the same.
HBITMAP hBitmapOld = (HBITMAP)::SelectObject(hDC, hBitmap); //select a bitmap
HFONT hFont = (HFONT)::SelectObject(hDC, hFont); //select the font.
everything is the same.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 33

Expert Comment

by:pgnatyuk
ID: 24870722
Try to debug and get in into the MFC code here: memDC.DeleteDC();
I don't have the VS right now to check, but theorethically it is possible that after ::DeleteDC the internal HDC variable was not assigned to NULL and BoundChecker complains about it.
Actually, I think I'm wrong. BoundChecker is a very good tool, but it is not always possible to make this app absolutely happy.
0
 

Author Comment

by:PMH4514
ID: 24871228
BoundChecker? I am unfamiliar. An MFC app, the snippet I posted, MBCS character set does not show the leak. By "leak" I am referring to watching the mem usage column in Windows Task Manager. It grows very rapidly with each iteration. The Unicode build of the same code shows the leak.  I'll step into the code and see!
0
 
LVL 33

Expert Comment

by:pgnatyuk
ID: 24872312
I think the growing memory usage you see in the task manager is not related to this CreateCompatibleDC code. It can be something else. I tested just a small app with this code - I have an error detection tool.
Actually, the books say that you need to take the DC from the window by using the GetDC function, then create the compatible DC (memory DC), ..., delete the memory DC, release the window DC. Do not leave any bitmap or a font in the memory DC - select "old" bimap and "old" font before the deleting.Otherwise the app will work slower and slower and then, the low-memory message box will jump.
0
 

Author Comment

by:PMH4514
ID: 24872707
But when I remove this code, the memory usage shown in task manager remains constant.

I have also tried this variant:

      CDC* pDC = GetDC();
      CDC memDC;
      memDC.CreateCompatibleDC(pDC);
      memDC.DeleteDC();

      ReleaseDC(pDC);
      pDC = NULL;


and it leaks as well.

I am aware not to leave objects in the memory DC. This test app doesn't even go as far as selecting anything into the DC, it just creates and destroys it. And the memory consumption continues to grow in task manager.
0
 
LVL 33

Accepted Solution

by:
pgnatyuk earned 125 total points
ID: 24876513
I made a simple dialog-based app with MFC, put a button and wrote the code from your example:
CDC memDC;
memDC.CreateCompatibleDC(NULL);
memDC.DeleteDC();

I tested it with Purify+. It shows: Summary of all memory leaks... {19880 bytes, 15 blocks}.
It does not matter, how many times to press on the button - once or 100 times. Purify+ shows the same. The report contains just usual things about the MFC: strings, _CRTDLL_INIT, etc.
I commented the DC code and got absolutely same report - 19880 bytes, 15 blocks.
BOOL CDC::DeleteDC() contains a very simple code:
::DeleteDC(Detach());
Detach removes the handle from an internal store - the HDC was added there on CreateCompatibleDC.

I build release configuration and checked it with the task manager. It shows memory usage 3.460K in the beginning and 17 GDI objects. I pressed on the button and the app took 8K more - it shows 3468K. Then, does not matter how many times to press on the button, the parameters in the task manager do not change.

In order to earn my points :), I made a small console app:
#include <windows.h>
#include <stdio.h>
int main()
{
    HDC hDC = NULL;
    for (int i = 0; i < 100; i++)
    {
        hDC = ::CreateCompatibleDC(NULL);
        ::DeleteDC(hDC);
        hDC = NULL;
     }
     return 0;
}
Purify+ still shows 532 bytes in calloc_dbg (_CRTDLL_INIT) as it was in the test with the MFC app.
I'm fully convinced that there is no memory leak in this code:
CDC memDC;
memDC.CreateCompatibleDC(NULL);
memDC.DeleteDC();
 
0
 

Author Comment

by:PMH4514
ID: 24879770
ok, thank you for everything!
0
 

Author Comment

by:PMH4514
ID: 24879895
Just to followup for future readers. Unicode or not, the following code in a loop does not show increasing memory usage in windows task manager:

   HDC hDC = NULL;
    hDC = ::CreateCompatibleDC(NULL);
    ::DeleteDC(hDC);
    hDC = NULL;


However, this code, in a loop, unicode only, does show substantially growing memory usage in task manager:

      CDC memDC;
      memDC.CreateCompatibleDC(NULL);
      memDC.DeleteDC();


0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Expand macro to ask for filename column 8 35
sum28 challenge 31 96
sumHeights2  challenge 7 76
Annoying "thing" blocks my view 4 51
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now