I have a piece of C++ code that deallocates memory as follows
for (int i = Pages-1; i >= NewPages; i--)
{
LPVOID p = m_Pages[i];
free(p);
}
While the code works ok, when called from an exception handler, it runs very slowly. Looking at task manager while single stepping through the above loop, the amount of physical memory used by the process (Mem Usage) increases with each call to free, whereas the virtual memory (VM Size) stays the same. Eventually the process terminates abnormally.
The code that allocates the memory that throws the exception is as follows;
for (int i = Pages; i < NewPages; i++)
{
LPVOID p = malloc(m_ElementsPerPage*m_ElementSize);
if (!p)
AfxThrowMemoryException( );
m_Pages.Add(p);
}
Now at a glance I suspect that if I reverse the ordering of the deallocation loop, such that the last block allocated is the first freed, I might avoid this problem. But is there any reason why process memory usage should increase with a call to free, and why calling free on a valid heap memory block should cause the program to terminate? (n.b. the termination could well be debugger related rather than the app itself).
Edit: The OS is Windows XP SP3, the compiler is MSVC++ 8
Edit2: A more complete version of the code is as follows;
void MyArray::ResizeArray(int NewPages)
{
int Pages = m_Pages.GetSize();
if (NewPages != Pages)
{
if (NewPages > Pages) // Grow the page array
{
for (int i = Pages; i < NewPages; i++)
{
LPVOID p = malloc(m_ElementsPerPage*m_ElementSize);
if (!p)
AfxThrowMemoryException( );
m_Pages.Add(p);
}
} else // Shrink the page array
{
for (int i = Pages-1; i >= NewPages; i--)
{
LPVOID p = m_Pages[i];
free(p);
}
m_Pages.SetSize(NewPages);
}
}
}
Your process can use two megabytes of memory. When malloc fails, the used memory will be near that value. If your computer has less physical memory, a lot of memory pages of that process will have been paged out to the disk.
While your exception handler frees back memory, the heap manager will touch all pages, bringing them back to physical memory. This will be slow.
This is what you are observing with the Task Manager. The column names are deceptives: VM Size is really private memory, which will not change because freed memory is not given back to the system by the Heap Manager (answering why would be a question by itself). Mem Usage is the size of the working set of the process, that is the physical memory used by that process. It will increase as pages are mapped back to physical memory from the page file.
You do not mention how the process terminates abnormally, but fragmentation may also occur in memory, which may explain that mallocs may continue to fail even after freeing your array.