Linux glibc 分配器的行为似乎很奇怪。希望有人可以对此有所了解。这是我拥有的源文件:
第一个.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;
}
第二个.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.cpp
我先运行,在它休眠后,我看到常驻内存大小:
当我编译 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 中变得碎片化,而在 second.cpp 中没有。但是,如果一个页面上的所有内存都被释放,那么该页面如何不被释放回内核呢?将内存交还给内核需要什么?如何修改 first.cpp(继续将 char* 放在列表中)以便将内存让给内核。