Link to home
Start Free TrialLog in
Avatar of mromeo
mromeo

asked on

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.
Avatar of Jaime Olivares
Jaime Olivares
Flag of Peru image

>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.
 
Avatar of Axter
Are you calling _CrtCheckMemory in your application destructor?
Avatar of mromeo
mromeo

ASKER

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?
Avatar of mromeo

ASKER

I added a few checkpoints and then call __CrtMemDifference/_CrtDumpMemStatistics, but I get no output.   What should I see in the debug window?
>>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.
Exactly what makes you think you'r getting a leak?
Avatar of mromeo

ASKER

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.
Avatar of mromeo

ASKER

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( );

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.
Also add a TRACE before calling _CrtCheckMemory.
char *a = new char[123456];
TRACE("****** Here comes memory leak dump ********");
_CrtDumpMemoryLeaks( );
Avatar of mromeo

ASKER

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.
Avatar of mromeo

ASKER

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?
Post your OnSize() event.
Avatar of mromeo

ASKER

I don't have one.
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
}
Avatar of mromeo

ASKER

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.

>>  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?
Avatar of mromeo

ASKER

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();

}
Avatar of mromeo

ASKER

It appears to be related to the toolbar.  When I comment out the code to create the toolbar, the problem goes away.
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);    
}
>>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.
Avatar of mromeo

ASKER

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.
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.
Avatar of mromeo

ASKER

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.
ASKER CERTIFIED SOLUTION
Avatar of NawalKishore1976
NawalKishore1976

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial