• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 433
  • Last Modified:

How do you detect resource leaks in an MFC MDI application?

Hi everyone.  I have an MDI application which has a drag/drop interface.  The problem that I'm having is that when I start dragging objects around on my View, memory starts growing very quickly.  The program doesn't have any detectable memory leaks that are obvious to me (ie.  all 'operator new's' are matched up with operator 'delete') and the program doesn't report any memory leaks when I exit the program.  I am suspecting that I am leaking other resources, such as GDI objects, fonts, brushes, etc...  Does anybody have any good ideas about how I can go about detecting resource leaks?  The program is fairly large, so it's hard to isolate the exact moment where it starts growing.

Let me know if there is other information that I can give you that may be helpful.  Thanks.
0
mromeo
Asked:
mromeo
  • 12
  • 7
  • 5
  • +1
1 Solution
 
Jaime OlivaresSoftware ArchitectCommented:
>Does anybody have any good ideas about how I can go about detecting resource leaks?  
Yes, best option is to read carefully your code, I think

in every function that works with drag and drop, you must ensure to deselect every resource type like: bitmaps, pens, brushes, fonts, etc.
So, every first time you select and object in a function (with SelectObject, saving previous object) you have to unselect it using SelectObject again.
 
0
 
AxterCommented:
Are you calling _CrtCheckMemory in your application destructor?
0
 
mromeoAuthor Commented:
Yes, I'm calling it in ExitInstance.  It doesn't give me any output to the output window.  Is there sometng I else I need to call to use it?
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
mromeoAuthor Commented:
I added a few checkpoints and then call __CrtMemDifference/_CrtDumpMemStatistics, but I get no output.   What should I see in the debug window?
0
 
AxterCommented:
>>Is there sometng I else I need to call to use it?

No, that should do it.

>> What should I see in the debug window?

You should get a message saying memory leak detected, and it should include a file name and line count.

You can force it to give you a leak by adding the following in your ExitInnstance function:
int *dummy = new[12345];

And don't delete it.
Then you'll see what the leak meassage should look like.
0
 
AxterCommented:
Exactly what makes you think you'r getting a leak?
0
 
mromeoAuthor Commented:
Well, it's possible that it's not a leak, but something is making memory grow very quickly in my application.  When I start dragging objects in my main View, memory starts growing by about 100k every 5 seconds.  That's before I even do the Drop.  It happens during OnDragOver.  I have been going over this code so carefully, and I can't figure out what's doing it.  I'm trying to figure out if its a system resource or something.  I don't know where to look next.
0
 
mromeoAuthor Commented:
I put an intentional leak right before I call _CrtDumpMemoryLeaks and it didn't tell me that I leaked anything.  Something isn't right.

      char *a = new char[123456];

      int ret = _CrtCheckMemory();
       _CrtDumpMemoryLeaks( );

0
 
AxterCommented:
Remove all other _Crt??? function calls, and only make the _CrtDumpMemoryLeaks() after the created memory leak.

You should also comment out any other _Crt??? code in your entire app.
One of them could be causing the problem.

You should just do the _CrtDumpMemoryLeaks() call by itself.
0
 
AxterCommented:
Also add a TRACE before calling _CrtCheckMemory.
char *a = new char[123456];
TRACE("****** Here comes memory leak dump ********");
_CrtDumpMemoryLeaks( );
0
 
mromeoAuthor Commented:
Ok, well, I got rid of the couple of minor leaks that I had.  Nothing has really changed.  When I start dragging objects around (which are CStatic objects), memory starts growing very rapidly.  As soon as I release the mouse and OnDrop is called.  It stops growing.  Where would you start looking?  I've been over and over this code.
0
 
mromeoAuthor Commented:
Ok, well, it appears to be totally unrelated to Dragging.  If I simply start resizing the main window (which has NO MDI windows open), memory start to grow.  I don't really know what to make of this.  Has anybody ever seen the app grow just by resizing the main FrameWnd?
0
 
Jaime OlivaresSoftware ArchitectCommented:
Post your OnSize() event.
0
 
mromeoAuthor Commented:
I don't have one.
0
 
Jaime OlivaresSoftware ArchitectCommented:
then it is your paint function, every time you drag the mouse to resize, a paint is made.
You can try:

CYourView::OnPaint()    // I suposse you have implemented this function, or could be OnPaint
{
     ::MessageBeep(MB_OK);

     // All your code here
}
0
 
mromeoAuthor Commented:
No, no, no.  I don't even have a view window open.  All I have is the MainFrame.  No views, no documents, etc have even been created.  All I'm doing is dragging the lower right corner to resize the window and the memory just grow and grow and grow.  I have no OnSize method and only one OnPaint method which is not being called.  I'm using Spy++ to try to figure out what other messages are being sent.  I tried a smaller test mdi application, and it does not happen with that program.

0
 
Jaime OlivaresSoftware ArchitectCommented:
>>  I am suspecting that I am leaking other resources, such as GDI objects, fonts, brushes, etc...  Does anybody have any
>> good ideas about how I can go about detecting resource leaks?

Hmm, since you mentioned GDI objects, I supossed you had a painting function.
Then, if you say you have not child windows (doc/view), could you post your entire CMDIFrameWnd implementation?
0
 
mromeoAuthor Commented:
Right, that's what I thought it was until I realized it was happening even without the View window open.  

Here's the code.  Don't know how much it will help out of context:


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
      //{{AFX_MSG_MAP(CMainFrame)
      ON_WM_CREATE()
      ON_COMMAND(ID_FILE_CHOOSE_URL, OnFileChooseUrl)
      ON_COMMAND(ID_WINDOW_TILE_VERT, OnWindowTileVert)
      ON_WM_CLOSE()
      ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
      ON_COMMAND(ID_FILE_SAVEALL, OnFileSaveall)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

static UINT indicators[] =
{
      ID_SEPARATOR,           // status line indicator
      ID_INDICATOR_DATABASE,
      ID_INDICATOR_POS,
      ID_INDICATOR_CAPS,
      ID_INDICATOR_NUM,
      ID_INDICATOR_SCRL,
};
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
}

CMainFrame::~CMainFrame()
{
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
      if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
            return -1;
      
      if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
            | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
            !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
      {
            TRACE0("Failed to create toolbar\n");
            return -1;      // fail to create
      }

      if (!m_wndStatusBar.Create(this) ||
            !m_wndStatusBar.SetIndicators(indicators,
              sizeof(indicators)/sizeof(UINT)))
      {
            TRACE0("Failed to create status bar\n");
            return -1;      // fail to create
      }

      // create the main toolbar.
      m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
      CString toolbarTitle;
      toolbarTitle.LoadString(IDR_MAINFRAME);
      m_wndToolBar.SetWindowText (toolbarTitle);

      EnableDocking(CBRS_ALIGN_ANY);
      DockControlBar(&m_wndToolBar);

      // set the window placment.
      WINDOWPLACEMENT wp;
      if (ReadWindowPlacement(&wp))
            SetWindowPlacement(&wp);

      return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
      if( !CMDIFrameWnd::PreCreateWindow(cs) )
            return FALSE;
      
      return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
      CMDIFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
      CMDIFrameWnd::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers

void CMainFrame::OnFileChooseUrl()
{
      // display the URL dialog box.
      CURLDialog      urlDlg;
      if (urlDlg.DoModal() == IDOK)
      {
      }
}

void CMainFrame::OnWindowTileVert()
{
      MDITile(MDITILE_VERTICAL);      
}

void CMainFrame::OnClose()
{
      WINDOWPLACEMENT    wp;

    // before it is destroyed, save the position of the window
    wp.length = sizeof wp;

    if ( GetWindowPlacement(&wp) )
    {
        if ( IsIconic() )
          // never restore to Iconic state
          wp.showCmd = SW_SHOW ;

        if ((wp.flags & WPF_RESTORETOMAXIMIZED) != 0)
          // if maximized and maybe iconic restore maximized state
          wp.showCmd = SW_SHOWMAXIMIZED ;

        // and write it to the .INI file
        WriteWindowPlacement(&wp);
    }
          
      CMDIFrameWnd::OnClose();
}

BOOL CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT *pwp)
{
      return CAppPreferences::SaveWindowPosition(pwp, STR_MAINWIN_POS);
}

BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT *pwp)
{
      return CAppPreferences::GetWindowPosition(pwp, STR_MAINWIN_POS);      
}


void CMainFrame::SetStatusBar(int pane, CString &text)
{
      m_wndStatusBar.SetPaneText(pane, text);
}


void CMainFrame::OnFileClose()
{
      // check to see how many documents are open.
      // when there are none left, change the status bar
      // to read the current url db value.

      CDocument *doc = GetActiveDocument();
      if (doc == NULL)
      {
            CString prefsURL = CAppPreferences::Fetch_GetModulesURL();
            SetStatusBar(1, prefsURL);
      }
}

void CMainFrame::OnFileSaveall()
{
      MessageBox("Save All Not Yet Implemented");

      // need to get all documents and tell each one to save
      CScreenMaintenanceApp *theApp = static_cast<CScreenMaintenanceApp *>(AfxGetApp());
      
      theApp->SaveAllModified();

}
0
 
mromeoAuthor Commented:
It appears to be related to the toolbar.  When I comment out the code to create the toolbar, the problem goes away.
0
 
Jaime OlivaresSoftware ArchitectCommented:
Don't what are these functions (maybe this: http://www.codeproject.com/dialog/windowpres.asp) but you can try to remove them temporarily:

BOOL CMainFrame::WriteWindowPlacement(WINDOWPLACEMENT *pwp)
{
     return CAppPreferences::SaveWindowPosition(pwp, STR_MAINWIN_POS);
}

BOOL CMainFrame::ReadWindowPlacement(WINDOWPLACEMENT *pwp)
{
     return CAppPreferences::GetWindowPosition(pwp, STR_MAINWIN_POS);    
}
0
 
Jaime OlivaresSoftware ArchitectCommented:
>>It appears to be related to the toolbar.  When I comment out the code to create the toolbar, the problem goes away.
If your toolbar is a custom toolbar, it could be.
0
 
mromeoAuthor Commented:
What do you mean by "custom" toolbar?  I haven't done anything special to it.  I have a member variable called m_wndToolBar.  All the code that deals with it is in the code I posted.
0
 
Jaime OlivaresSoftware ArchitectCommented:
What do you mean by "custom" toolbar?
I mean some derived toolbar that you can obtain in the internet, some of these objects have memory leaks.
But if you say it is a standard CToolbar object, then it is strange that it produces a memory leak.
You toolbar buttons must be related to some application functions, am I correct?
If so, maybe you have some 'OnUpdateSomeCommand()' functions to manage buttons state, there could be a possible point of leakage.
0
 
mromeoAuthor Commented:
It's not that either.  All my ::OnUpdateXXX methods are in the view or document classes.  I guess I'm goint to ave to rip this code apart, line by line to figure out what is going on.  Maybe I need to re-assemble the toolbar to see at what point this memory problem starts.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

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