Wir haben einige Speicherprobleme, wenn std::vector
ein Feld einer Klasse ist. Wir füllen diesen Vektor mit vielen Daten, die an einem bestimmten Punkt des Programms freigegeben werden müssen. Obwohl die Vektorkapazität Null ist, wird der Speicher jedoch nicht freigegeben oder vollständig freigegeben.Speicher wurde beim Leeren von std :: vector in einer benutzerdefinierten Klasse nicht freigegeben
Hier haben Sie eine vereinfachte Version unseres Programms. Wie Sie sehen können, hat die Klasse Foo
nur ein Feld: a std::vector<int>
. Wenn wir einen std::vector<Foo>
erstellen und ihn mit Foo
Objekten füllen, wird der Speicher nicht vollständig freigegeben, wenn wir den Vektor innerhalb jedes Objekts leeren.
Wir haben die Speicherbelegung mithilfe des Aktivitätsmonitors gemessen und Sie können neben jeder Protokollzeile die Anzahl der in jeder Phase verwendeten Bytes sehen. Außerdem haben wir eine weitere Version hinzugefügt, in der wir keine Objekte der Klasse Foo
verwenden, und in diesem Fall wird der Speicher perfekt freigegeben.
#include <iostream>
#include <vector>
class Foo {
public:
std::vector<int> container;
};
int main() {
int n1 = 1000;
int n2 = 100000;
{
std::vector<Foo> foos;
std::cerr << "starting" << std::endl; // 160 KiB
std::cin.get();
for (int i = 0; i < n1; i++){
Foo foo;
foo.container.assign(n2, 666);
foos.push_back(foo);
}
std::cerr << "foos filled" << std::endl; // 382.1 MiB
std::cin.get();
for (unsigned int i = 0; i < foos.size(); i++){
std::vector<int>().swap(foos[i].container);
}
std::cerr << "foos emptied" << std::endl; // 195.7 MiB
std::cin.get();
}
std::cerr << "foos destroyed?" << std::endl; // 296 KiB
std::cin.get();
{
std::vector<std::vector<int> > foos;
std::cerr << "starting" << std::endl; // 296 KiB
std::cin.get();
{
std::vector<int> aux;
aux.assign(n2, 666);
foos.assign(n1, aux);
}
std::cerr << "foos filled" << std::endl; // 382.1 MiB
std::cin.get();
for (unsigned int i = 0; i < foos.size(); ++i) {
std::vector<int>().swap(foos[i]);
}
std::cerr << "foos emptied" << std::endl; // 708 KiB
std::cin.get();
}
std::cerr << "foos destroyed?" << std::endl; // 708 KiB
std::cin.get();
return 0;
}
Wenn es hilft, verwenden wir g ++ 4.8.4 unter Ubuntu 14.04 64-Bit. Die spezifische Speicherbelegung hängt davon ab, ob wir C++ 11 oder C++ 98 verwenden, aber das gleiche Phänomen tritt in beiden Fällen auf.
Irgendwelche Ideen, was passiert und wie diese Erinnerung gewaltsam wiederhergestellt werden kann, wenn nötig?
EDIT: Beachten Sie, dass Speicher meist in der Tat zurückgegeben wird, wenn wir alle Objekte der Klasse Foo
zerstören, aber in unserer realen Welt Problem müssen wir noch den Rest des Inhalts der Foo
-Analogon Klasse.
Wie haben Sie gemessen? Gewöhnlich wird jeder Speicher, der vom Prozess vom Betriebssystem erworben wurde, nicht _ zurückgewiesen _, wenn der Speicher intern freigegeben wird. –
Es ist ein Teil des Lebens, fürchte ich. Aber verursacht es tatsächlich ein Problem? Moderne Betriebssysteme und C++ Laufzeiten sind gut darin, Speicher freizugeben, wenn sie es wirklich brauchen. – Bathsheba
Das Freigeben von Speicher in einer Anwendung muss nicht den gesamten Speicher zurück an das Betriebssystem freigeben, da die Zuordnungen auf der Betriebssystemebene wahrscheinlich größere Abschnitte sind. – drescherjm