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?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage