Linux Allocator gibt keine kleinen Speicherbereiche frei
Der Linux-Glibc-Allokator scheint sich merkwürdig zu verhalten. Hoffentlich kann jemand Licht ins Dunkel bringen. Hier ist die Quelldatei, die ich habe:
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;
}
Ich kompiliere beide:
$ g++ -o first first.cpp $ g++ -o second second.cpp
Ich renne zuerst und nachdem es geschlafen hat, sehe ich die Größe des residenten Speichers:
Wenn ich first.cpp kompiliere und starte, schaue ich mit ps auf den Speicher:
$ ./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
Beachten Sie die Größe des residenten Speichers. In erster Linie ist die Größe des residenten Speichers 53016k. im zweiten ist es 1024k. Zuerst haben Sie die Zuweisungen aus irgendeinem Grund nie wieder an den Kernel zurückgegeben.
Warum gibt das erste Programm den Speicher nicht an den Kernel ab, das zweite Programm jedoch? Ich verstehe, dass das erste Programm eine verknüpfte Liste verwendet und die verknüpfte Liste wahrscheinlich einige Knoten auf derselben Seite wie die Daten zuordnet, die wir freigeben. Diese Knoten sollten jedoch freigegeben werden, da wir diese Knoten entfernen und dann die verknüpfte Liste löschen. Wenn Sie eines dieser Programme über valgrind ausführen, kommt es ohne Speicherlecks zurück. Was wahrscheinlich passiert ist, dass Speicher in first.cpp fragmentiert wird, in second.cpp nicht. Wenn jedoch der gesamte Speicher auf einer Seite freigegeben wird, wie wird diese Seite nicht an den Kernel zurückgegeben? Was braucht es, damit der Speicher wieder an den Kernel zurückgegeben wird? Wie kann ich first.cpp ändern (weiterhin die Zeichen * in einer Liste ablegen), so dass der Speicher an den Kernel übergeben wird?