0

Not at all an expert in MFC, but I have been put on a project to revamp the GUI in one of our applications. I am building a dialog with a CListCtrl and seeing memory issues, even though the list I am displaying will contain usually no more than about 200 rows. There are 4 columns, and I'm attaching an associated int value with each row using SetItemData in order to do filtering.

When I filter, I repopulate the list by first calling DeleteAllItems() and then looping to populate with only the data that passes my filter. When I watch in the Performance tab in the system Task Manager dialog, I see memory taken up when the dialog opens. Seems like more than I would imagine, but anyway. When I filter, if nothing is shown as a result of the chosen filter, the memory is never reclaimed by the system, according to Task Manager Performance tab. When I change the filter to show some rows, I see more memory taken. I never see memory given back to the system. If I continue to filter, I will eventually see the memory usage go almost to full usage, and I will get an Out of memory dialog that MFC puts up.

I have seen this out of memory dialog also when I am just scrolling up and down a lot in a full (unfiltered) view of the data. For each scrolling, the list control is somewhat slow to repaint, and the memory usage in the Performance tab goes up, even though I'm not adding any data.

Does anyone have a feeling for what might be going on here? I'm stumped at the moment. The following is basically what I'm doing in my code. I am not otherwise managing the view:

m_ListCtrl.DeleteAllItems();
for (int i=0; i<mylist.size(); i++)
{
    // here I get all the data from the current record in mylist, one of them being an int value iSecs.
    ...

    // insert data item
    int row = m_ListCtrl.InsertItem(i, sTimeStamp.c_str());
    BOOL ok = m_ListCtrl.SetItem(i, 1, sErrorCode.c_str());
    ok = m_ListCtrl.SetItem(i, 2, sErrorLevel.c_str());
    ok = m_ListCtrl.SetItem(i, 3, sDescription.c_str());
    // set the timestamp seconds as item data for later filtering for display
    ok = m_ListCtrl.SetItemData(row, (DWORD_PTR)iSecs);
}
bmahf
  • 965
  • 2
  • 11
  • 27
  • 1
    _here I get all the data from the current record in mylist_ Could the problem lie there? The MFC calls you are making are just wrappers round the various `LVM_xxx` messages (eg LVM_DELETEALLITEMS). They don't actually do anything. – Paul Sanders Sep 26 '18 at 23:24
  • 4
    `DeleteAllItems` does a 'shallow' delete. Notably, it won't delete whatever [LVITEM](https://learn.microsoft.com/en-us/windows/desktop/api/commctrl/ns-commctrl-taglvitemw)'s *lParam* member points to. Same goes for *piColFmt*. The code posted doesn't appear to be leaking any resources. We need to see a [mcve]. – IInspectable Sep 27 '18 at 08:14
  • Which "out of memory dialog" are you refering to? There must be something in the code you didn't show here. – Jabberwocky Sep 27 '18 at 08:51
  • No, the out of memory dialog is one that MFC pops up. I have seen similar dialogs like when I have tried creating a dialog with an IDD definition that exists in resource.h but for which a dialog definition doesn't exist in the .rc file. They do this in order to avoid crashing the application, and yet to still inform the user that something has gone wrong. – bmahf Sep 27 '18 at 12:53
  • IInspectable - thanks for the link. I will take a look at that and let you know about my findings. – bmahf Sep 27 '18 at 12:55

1 Answers1

1

Heap memory is not usually returned to the OS when free() (or delete) is called. It is retained in the heap. See also this answer. So on the first populate/delete-all operation you will see allocated memory increase. But on subsequent cycles, the memory use should be fairly stable.

Microsoft's MFC libraries have been around for more than a decade, if there was a memory leak in CListCtrl::DeleteAllItems() it would have been found in the 90's.

You can check the memory usage in-program with a few API calls.

The memory leak is probably caused by this line:

ok = m_ListCtrl.SetItemData(row, (DWORD_PTR)iSecs);

In MFC Item Data is the responsibility of the user to clean up. You will need to iterate through every item in your list freeing (or deleteing) the user-data before calling the API to delete the list item(s). Of course you can free the allocated data some other way too.

As your program continually adds and removes items from the list, it is leaking the ItemData(s) associated with each list entries.

Kingsley
  • 14,398
  • 5
  • 31
  • 53