I am having a strange C++ new/delete question which is at some circumstance I delete (deconstruct) an object from pointer array but the memory seems not to be released. Please see the code and comments below.
If run all the steps from Step-1 to Step-6, the memory is NOT released after Step-4 or Step-5.
If run Step-1, Step-2, Step-3, Step-4 and Step-6 (comment and skip Step-5), the memory is NOT released after Step-4 or Step-6.
If run Step-3, Step-4 and Step-6 (comment and skip Step-1, Step-2 and Step-5), the memory can be released as expected after Step-4 or Step-6.
If run all the steps from Step-1 to Step-6, but at Step-3 the new string size is larger than previous size at Step-1, the memory can be released as expected after Step-4 or Step-5 or Step-6.
So in general, if NOT run Step-1 and Step-2, everything seems fine. But If run Step-1 and Step-2 before, something wired happens that the memory is NOT released unless the new string size is larger than previous size at Step-1.
#include <iostream>
#include <list>
#include <unistd.h>
struct MyClass {
std::string str;
MyClass() {}
~MyClass() {}
};
int main(int argc, char* argv[]) {
std::list<MyClass*> mylist;
// Step-1: create 100 MyClass pointer array,
// then construct 20 MyClass objects with 1MB's string for each
// and put them into a list
MyClass** pt1 = new MyClass*[100];
for (int i = 0; i < 20; ++i) {
std::string tmp_str(1024*1024, 'a'); // 1MB
pt1[i] = new MyClass();
pt1[i]->str = tmp_str;
mylist.push_back(pt1[i]);
}
std::cout << "Step-1: creating done: " << mylist.size() << std::endl;
sleep(10); // now check the memory usage of this process, it should use
// about 20MB memory
// Step-2: delete all the MyClass objects from the list,
// then delete pt1
while (1) {
std::list<MyClass*>::iterator it = mylist.begin();
if (it == mylist.end())
break;
delete *it;
mylist.erase(it);
}
delete [] pt1;
pt1 = NULL;
std::cout << "Step-2: deleting done, left: " << mylist.size()
<< std::endl;
sleep(10); // now check the memory usage (RSS) of this process,
// it should reduce about 20MB memory
// Step-3: create another 100 MyClass pointer array,
// then construct 10 MyClass objects with 1MB's string for each
// and put them into a list
MyClass** pt2 = new MyClass*[100];
for (int i = 0; i < 10; ++i) {
std::string tmp_str2(1024*1024, 'b');
pt2[i] = new MyClass();
pt2[i]->str = tmp_str2;
mylist.push_back(pt2[i]);
}
std::cout << "Step-3: creating done: " << mylist.size() << std::endl;
sleep(10); // now check the memory usage (RSS) of this process
// it should use about 10MB memory
// Step-4: delete 4 MyClass objects from the list, NOT all of them
int j = 0;
while (1) {
std::list<MyClass*>::iterator it = mylist.begin();
if (it == mylist.end() || ++j == 5)
break;
delete *it;
mylist.erase(it);
}
std::cout << "Step-4: deleting done, left: " << mylist.size()
<< std::endl;
sleep(10); // now check the memory usage (RSS) of this process,
// we expect it should reduce about 4MB memory,
// but it still uses about 10MB memory and seems
// no memory is freed.
// Step-5: delete all the left MyClass objects from the list
while (1) {
std::list<MyClass*>::iterator it = mylist.begin();
if (it == mylist.end())
break;
delete *it;
mylist.erase(it);
}
std::cout << "Step-5: deleting done, left: " << mylist.size()
<< std::endl;
sleep(10); // now check the memory usage (RSS) of this process,
// we expect it should reduce about 10MB memory,
// but it still uses about 10MB memory and seems
// no memory is freed.
// Step-6: delete pt2
delete [] pt2;
pt2 = NULL;
std::cout << "Step-6: deleting array done" << std::endl;
sleep(10); // now check the memory usage (RSS) of this process,
// if we run Step-5 before, then the memory will reduce
// about 10MB,
// but if we didn't run Step-5 before, then the memory will
// still be about 10MB and seems no memory is freed.
return 0;
}