The Linux glibc allocator seems to be behaving weirdly. Hopefully, someone can shed some light on this. Here is the source file that I have:
first.cpp:
#include <unistd.h>
#include <stdlib.h>
#include <list>
#include <vector>
int main() {
std::list<char*> ptrs;
for(size_t i = 0; i < 50000; ++i) {
ptrs.push_back( new char[1024] );
}
for(size_t i = 0; i < 50000; ++i) {
delete[] ptrs.back();
ptrs.pop_back();
}
ptrs.clear();
sleep(100);
return 0;
}
second.cpp:
#include <unistd.h>
#include <stdlib.h>
#include <list>
int main() {
char** ptrs = new char*[50000];
for(size_t i = 0; i < 50000; ++i) {
ptrs[i] = new char[1024];
}
for(size_t i = 0; i < 50000; ++i) {
delete[] ptrs[i];
}
delete[] ptrs;
sleep(100);
return 0;
}
I compile both:
$ g++ -o first first.cpp $ g++ -o second second.cpp
I run first, and after it's sleeping, I see the resident memory size:
When I compile first.cpp, and run it, I look at memory with ps:
$ ./first&
$ ps aux | grep first
davidw 9393 1.3 0.3 64344 53016 pts/4 S 23:37 0:00 ./first
$ ./second&
$ ps aux | grep second
davidw 9404 1.0 0.0 12068 1024 pts/4 S 23:38 0:00 ./second
Notice the resident memory size. In first, the resident memory size is 53016k. in second, it is 1024k. First never released the allocations back to the kernel for some reason or another.
Why does the first program not relinquish memory to the kernel, but the second program does? I understand that the first program uses a linked list and the linked list probably allocates some nodes on the same page as the data we're freeing. However, those nodes should be freed, as we're popping those nodes off, then clearing the linked list. If you run either of these programs through valgrind, it comes back with no memory leaks. What is probably happening is memory gets fragmented in first.cpp that doesn't in second.cpp. However, if all memory on a page is freed, how does that page not get relinquished back to the kernel? What does it take for memory to get relinquished back to the kernel? How can I modify first.cpp (continuing to put the char*'s in a list) so that the memory is relinquished to the kernel.