Linux的glibc分配器似乎表现得有些奇怪,希望有人能解释一下。这是我拥有的源文件:
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;
}
我同时编译:
$ g++ -o first first.cpp $ g++ -o second second.cpp
我运行first,在它睡眠时,我查看它的驻留内存大小:
当我编译first.cpp并运行它时,我使用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
请注意驻留内存大小。第一个程序中,驻留内存大小为53016k;而在第二个程序中,它是1024k。由于某种原因,第一个程序从未将分配的内存释放回内核。
为什么第一个程序不会将内存释放回内核,而第二个程序会?我知道第一个程序使用了链表,链表可能在和我们要释放的数据相同的页面上分配了一些节点。但是,当我们弹出这些节点并清除链表时,那些节点应该会被释放掉。如果你通过valgrind运行这两个程序,它们都不会出现内存泄漏。可能发生的情况是,第一个程序中的内存被碎片化了,而第二个程序中没有。然而,如果页面上的所有内存都被释放了,那么如何才能将该页面释放回内核呢?内存何时才能被释放回内核?我该如何修改first.cpp(继续将char*放在列表中),以便将内存释放回内核。
std::list<char*>().swap(ptrs)
。 - jxhint main() { { std::list 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();
std::list().swap(ptrs);
}
sleep(100);
return 0;
}
运行ps命令的结果相同:davidw 9961 0.0 0.3 64344 53016 pts/4 S 00:31 0:00 ./first
- user1418199malloc
/free
对的文章,同样的逻辑也适用于new
/delete
对。 - user743382