Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CDialog memory leaks in VC10

We are upgrading from VC8 to VC10 and have found a number of memory leaks that seem to be CDialog related. The simplest example of this is demonstrated with the following code using a CDialog that just has a number of buttons. In VC10 this leaks, but in VC8 it doesn't:

for (int i = 0; i < 5000; ++i) {
  CDialog* dialog = new CDialog;
  dialog->Create(IDD_LEAKER, 0);
  dialog->DestroyWindow();
  delete dialog;
}

Memory usage keeps rising and the example dialog we have with about 30 buttons leaks 10s of Mb.

Note that the above is a test example where we have stripped out all of our dialog handling code, in our real code we have a derived class and use PostNcDestroy().

Oddly neither of the following code examples leak in either VC8 or VC10:

CDialog* dialog = new CDialog;
for (int i = 0; i < 5000; ++i) {
  dialog->Create(IDD_LEAKER, 0);
  dialog->DestroyWindow();
}
delete dialog;

for (int i = 0; i < 5000; ++i) {
  CDialog* dialog = new CDialog;
  delete dialog;
}

What are we missing here?

like image 543
lilburne Avatar asked Aug 18 '11 12:08

lilburne


1 Answers

This appears to be down to the way that MFC manages its handle maps:

What is the lifetime of a CWnd obtained from CWnd::FromHandle?

If you wait long enough for your application to become idle, you do get your memory back, i.e. it's not really a leak. However, as you have observed, while Visual C++ 2010 continues to consume more and more memory - until the maps are tidied in OnIdle() - this doesn't appear to happen in Visual C++ 2008.

Debugging an application containing your code does show that there are a lot more objects in the HWND temporary map in the VC 10 version than there are in the VC 9 version.

The handle map code (winhand.cpp) doesn't appear to have changed between the two versions but there's lots of code in MFC that uses it!

Anyway, assuming that you really want to run your program like this - I guess you're running in some kind of automated mode? - then you'll want to force the garbage collection at appropriate intervals. Have a look at this entry on MSDN:

http://msdn.microsoft.com/en-us/library/xt4cxa4e(v=VS.100).aspx

CWinThread::OnIdle() actually calls this to tidy things up:

AfxLockTempMaps();
AfxUnlockTempMaps(/*TRUE*/);
like image 112
Nick Avatar answered Sep 20 '22 23:09

Nick