Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1661
  • Last Modified:

CreateCompatibleDC memory leak?

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
PMH4514
Asked:
PMH4514
  • 7
  • 5
1 Solution
 
pgnatyukCommented:
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
 
ZoppoCommented:
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
 
PMH4514Author Commented:
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
PMH4514Author Commented:
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
 
PMH4514Author Commented:
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
 
pgnatyukCommented:
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
 
pgnatyukCommented:
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
 
PMH4514Author Commented:
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
 
pgnatyukCommented:
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
 
PMH4514Author Commented:
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
 
pgnatyukCommented:
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
 
PMH4514Author Commented:
ok, thank you for everything!
0
 
PMH4514Author Commented:
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

Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now