2014-09-24 8 views
22

Wenn Sie einen sehr großen Vektor von Vektoren verwenden, haben wir gefunden, dass ein Teil des Speichers nicht freigegeben wird.Enormes std :: vector <std::vector> gibt nicht alle Speicher auf Zerstörung frei

#include <iostream> 
#include <vector> 
#include <unistd.h> 

void foo() 
{ 
    std::vector<std::vector<unsigned int> > voxelToPixel; 
    unsigned int numElem = 1<<27; 
    voxelToPixel.resize(numElem); 

    for (unsigned int idx=0; idx < numElem; idx++) 
     voxelToPixel.at(idx).push_back(idx); 

} 

int main() 
{ 
    foo(); 
    std::cout << "End" << std::endl; 
    sleep(30); 
    return 0; 
} 

Das lässt etwa 4 GB Speicher hängen, bis der Prozess endet.

Wenn wir die for Linie

for (unsigned int idx=0; idx < numElem; idx++) 
    voxelToPixel.at(0).push_back(idx); 

der Speicher freigegeben wird, ändern.

Verwendung gcc-4.8 auf einem Linux-Computer. Wir haben htop verwendet, um die Speichernutzung auf einem Computer mit 100 GB RAM zu verfolgen. Sie benötigen ca. 8 GB RAM, um den Code auszuführen. Können Sie das Problem reproduzieren? Irgendwelche Ideen, warum das passiert?

EDIT: Wir haben gesehen, dass das nicht in einem Mac (mit entweder gcc oder clang) passiert. Auch unter Linux wird der Speicher freigegeben, wenn wir zweimal foo aufrufen (geschieht aber das dritte Mal).

+1

Können Sie dies mit einem kleineren Beispiel reproduzieren? – stefan

+0

@stefan kleiner wie? in der Anzahl der Elemente? Ich habe gesehen, dass dies bei 2^25 passiert, aber für kleinere ist es schwer zu sagen. – quimnuss

Antwort

27

Kleine Zuweisungen (bis zu 128kb, denke ich) werden von einem In-Process-Heap verwaltet und werden nicht an das Betriebssystem zurückgegeben, wenn sie freigegeben werden; Sie werden in den Heap zur Wiederverwendung innerhalb des Prozesses zurückgegeben. Größere Zuweisungen stammen direkt vom Betriebssystem (durch Aufruf von mmap) und werden bei der Freigabe an das Betriebssystem zurückgegeben.

In Ihrem ersten Beispiel muss jeder Vektor nur genügend Speicherplatz für einen einzelnen int reservieren. Sie haben hundert Millionen kleine Zuordnungen, von denen keine an das Betriebssystem zurückgegeben wird.

Im zweiten Beispiel, wenn der Vektor wächst, wird es viele Zuweisungen von verschiedenen Größen machen. Einige sind kleiner als der mmap Schwellenwert, diese bleiben im Prozessspeicher; aber da du das nur mit einem Vektor machst, wird das keine große Menge sein. Wenn Sie resize oder reserve verwenden, um den gesamten Speicher für jeden Vektor vor dem Auffüllen zuzuweisen, sollten Sie feststellen, dass der gesamte Speicher an das Betriebssystem zurückgegeben wird.

+0

Jeder der '1 << 27' inneren Vektoren enthält nur ein einziges 'int', also 'resize'/'reserve' würde in diesem Fall nicht helfen. Für den äußeren Vektor gibt es bereits eine "Größenänderung". –

+0

@MarkRansom: Whoops, du hast recht, ich habe den Code falsch gelesen. –

+0

@MikeSeymour Das klingt nach Richtig ... Weißt du, ob es eine Möglichkeit gibt, den Prozess zu zwingen, den unbenutzten Heapspeicher freizugeben? Was passiert, wenn das Betriebssystem nicht mehr genügend Arbeitsspeicher hat? – quimnuss

Verwandte Themen