views:

46

answers:

2

If I have a native C++ program and look at it's initial "Private bytes" memory counter why would it not go back down to it's original value after an object has been created and then deleted?

For example if I have an application (32bit, Native C++ MFC ) that has two buttons. One in a loop that allocates 1,000,000 instances of an object and then the other button that other then deletes those same objects.

If I look at my Private bytes counters for the process I have the following 3 values:
.
Description.......... Private Bytes Count
============= ======================
App Started.................1,608K
Objects. created........33,176K
Objects. deleted..........2,520K

Leak of 912K ( 2520-1608 ) ?

Assuming that my code does not leak memory which I believe it is not why does the Private bytes count not go back to the EXACT initial value?

If I click on the two buttons again ( not having restarted the program ) ( 1st button creates another 1,000,000 objects ) and the second deletes them I have this:

Objects. created........33,472K
Objects. deleted..........2,552K

New Leak of ( 2552-2520 ) = 32K

I am just looking for an explanation on why the memory would not go back to the orginal value.

Sample Code ( some generated code stripped out to reduce noise ):

class Person
{
public:
   Person(void);
   ~Person(void);

   Person* Next;
   int A;
   int B;
   int C;
   int D;

};


class Cdelme_MFC2005_MemoryTestDlg : public CDialog
{
// some code stripped out here to simplify reading.

   Person* m_PeopleList_First;
   Person* m_PeopleList_Last;

public:
   afx_msg void OnBnClickedButtonAllocate();
   afx_msg void OnBnClickedButtonFree();
};


Cdelme_MFC2005_MemoryTestDlg::Cdelme_MFC2005_MemoryTestDlg(CWnd* pParent /*=NULL*/)
    : CDialog(Cdelme_MFC2005_MemoryTestDlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

   m_PeopleList_First = NULL;
   m_PeopleList_Last = NULL;

}


void Cdelme_MFC2005_MemoryTestDlg::OnBnClickedButtonAllocate()
{
   if ( m_PeopleList_First == NULL )
   {
      m_PeopleList_First = new  Person();
      m_PeopleList_First->A = 0;
      m_PeopleList_Last = m_PeopleList_First;
   }

   int MAX = 1000000;
   for (int i = 0; i <MAX ; i++)
   {
      Person* p = new Person();
      p->A = i;
      m_PeopleList_Last->Next = p;
      m_PeopleList_Last = p;
   }
}

void Cdelme_MFC2005_MemoryTestDlg::OnBnClickedButtonFree()
{
   Person* p = m_PeopleList_First;
   while ( p != NULL )
   {
      Person* pNext = p->Next;
      delete p;
      p = pNext;
   }
   m_PeopleList_First = NULL;
   m_PeopleList_Last = NULL;
}
+1  A: 

This is not an indication of a memory leak. The OS only counts the 4k-sized pages assigned to your process. The heap allocator running inside your process will request and release OS pages on your behalf. The heap manager may keep memory after you release it, to reuse it later for other objects.

You need to instrument your application to find memory leaks, and/or run long running stress tests to detect accumulating leaks.

jdv
Thanks for your input. I think your answer of the heap manager keeping the memory around for reuse sounds very possible. I will attempt to test this along with the answer from Jerry.
kevin
+1  A: 

You have a couple of problems here. First of all, when you delete memory, the standard library normally does not release that memory back to the OS. It normally retains ownership of that memory, but marks it as available for other allocations. Since you're apparently using MS VC++, you could use _heapwalk after you do your deletes to see the free blocks still in the process' heap. If you really want to, you could also call _heapmin to release (at least most of) that free memory back to the OS. Way back when (MS VC++ 4.0, if memory serves) MS had a version of the standard library that used the OS's memory management directly, but performance was dismal (to put it nicely), so that didn't last very long.

Second, MFC has a fair amount going on in the background where it allocates various "stuff" to make things work, but doesn't free them immediately afterwards (and since most of it is more or less invisible, there's no easy/direct way for you to free it either).

Jerry Coffin
Once again thanks for your input. You've given me a couple of useful items to follow up in my investigation ( _heapwalk and _heapMin ). I will modify my program and see the impact of the _heapmin.Regarding your second comment with the MFC I guess I could change my simple program to be a simple Win32 Console application to remove the MFC to reduce the number of variables in this equation.Thanks.
kevin
@kevin: I wouldnt remove MFC just jet. The MFC libraries have optional built in memory leak tracking. You get a log at application exit of all objects you failed to delete. Very handy. http://msdn.microsoft.com/en-us/library/c99kz476(VS.80).aspx
jdv
@jdv: Quite true. Though it's less known, you can get fairly similar things without MFC though (http://msdn.microsoft.com/en-us/library/x98tx3cf(VS.80).aspx).
Jerry Coffin
Thanks jdv for your response. I've enabled the runtime leak detection to confirm that "my" code is not leaking and it is not.
kevin