2016-11-19 4 views
1

Ich hasse es, das alte "hier ist ein Code, was ist los damit?" aber ich habe dieses Problem mehrere Tage lang ohne Fortschritt untersucht. Dieser Code stürzt normalerweise sofort ab, wenn der Debugger ausgeschaltet ist, obwohl gelegentlich ein Speicherplatz von einigen Stunden zur Verfügung steht, in dem er korrekt kompiliert und ausgeführt wird. Mit angeschlossenem gdb funktioniert es, aber verliert Speicher bei ungefähr 10 MB pro Sekunde und stürzt schließlich ab, wenn es ausläuft.Mysteriöses Speicherleck in C++ Datei Ausgabefunktion

Es ist definitiv diese Funktion; Solche Probleme treten nicht auf, wenn der einzige Aufruf an sie auskommentiert wird, und ein seltener Aufruf verzögert den Ausfall des Arbeitsspeichers.

//Write a frame of the animation to disk 
void draw_frame(int framenum) { 
    ofstream fout; 
    ostringstream fname; 
    fname << "D:\\frames\\" << framenum << ".data"; 
    fout.open(fname.str(), ios::binary | ios::out); 

    unsigned char ***frame; 
    frame = new unsigned char ** [WORLDSIZE]; 
    for (int x = 0; x < WORLDSIZE; x++) { 
     frame[x] = new unsigned char * [WORLDSIZE]; 
     for (int y=0; y < WORLDSIZE; y++) { 
      frame[x][y] = new unsigned char [3]; 
     } 
    } 

    unsigned long long ***colormix; 
    colormix = new unsigned long long ** [WORLDSIZE]; 
    for (int x = 0; x < WORLDSIZE; x++) { 
     colormix[x] = new unsigned long long * [WORLDSIZE]; 
     for (int y=0; y < WORLDSIZE; y++) { 
      colormix[x][y] = new unsigned long long [3]; 
      for (int z=0; z < 3; z++) { 
       colormix[x][y][z]=0; 
      } 
     } 
    } 

    for (vector<SmellyObject *>::iterator it = smellythings.begin(); it != smellythings.end(); ++it) { 
     SmellyObject *theobj = *it; 
     for (int x=0; x < WORLDSIZE; x++) { 
      for (int y=0; y < WORLDSIZE; y++) { 
       double scentlevel = scentmaps[theobj -> id][x][y]; 
       double colorlevel = (scentlevel/10000.0); 
       colormix[x][y][0] += theobj->r * colorlevel; 
       colormix[x][y][1] += theobj->g * colorlevel; 
       colormix[x][y][2] += theobj->b * colorlevel; 
      } 
     } 
    } 

    for (int x=0; x < WORLDSIZE; x++) { 
     for (int y=0; y < WORLDSIZE; y++) { 
      for (int z=0; z < 3; z++) { 
       //cout << colormix[x][y][z] << " "; 
       frame[x][y][z] = min(255.0, (colormix[x][y][z]/(double) smellythings.size())); 
      } 
     } 
    } 

    for (int x=0; x < WORLDSIZE; x++) { 
     for (int y=0; y < WORLDSIZE; y++) { 
      fout.write((char *) frame[x][y], 3); 
     } 
    } 

    fout.close(); 

    frame = new unsigned char ** [WORLDSIZE]; 
    for (int x = 0; x < WORLDSIZE; x++) { 
     frame[x] = new unsigned char * [WORLDSIZE]; 
     for (int y=0; y < WORLDSIZE; y++) { 
      for (int z=0; z < WORLDSIZE; z++) { 
       //delete[] &frame[x][y][z]; 
      } 
      delete[] frame[x][y]; 
     } 
     delete[] frame[x]; 
    } 
    delete[] frame; 

    colormix = new unsigned long long ** [WORLDSIZE]; 
    for (int x = 0; x < WORLDSIZE; x++) { 
     colormix[x] = new unsigned long long * [WORLDSIZE]; 
     for (int y=0; y < WORLDSIZE; y++) { 
      for (int z=0; z < WORLDSIZE; z++) { 
       //delete[] &colormix[x][y][z]; 
      } 
      delete[](colormix[x][y]); 
     } 
     delete[](colormix[x]); 
    } 
    delete[](colormix); 

    return; 
} 

WORLDSIZE 50 ist, und ist ein scentmapsstd::unordered_map Mapping ints (die .id Eigenschaft eines SmellyObject) x WORLDSIZE Arrays verdoppelt WORLDSIZE.

+0

Sie verwenden bereits 'vector', warum verwenden Sie' new [] 'und' delete [] 'in einigen Teilen des Codes? – krzaq

+0

Müssen Sie wirklich mit diesen Zeigern _to pointers_ __to pointers__ umgehen? Warum nicht stattdessen einen 'std :: vector' verwenden? In Ordnung, es könnte ziemlich erschreckende Formen wie 'std :: vector >>' nehmen, aber Sie müssen keinen Speicher für die Elemente zuweisen, was Ihnen viel Zeit sparen wird und wird beim Debuggen keine Kopfschmerzen verursachen. – ForceBru

+0

Autsch, wenn ich 'Char *** Frame' sehe, tut es mir weh ... Warum benutzt du 3 Ebenen der Indirektion? Kannst du nicht einfach Standard C++ Container verwenden? – kebs

Antwort

1
frame = new unsigned char ** [WORLDSIZE]; 

Sie ordnen dieses Array am Anfang der Funktion zu, und ordnen Sie alle seine drei Dimensionen zu, verschlingen eine große Menge an Speicher. später

Dann ...

fout.close(); 

frame = new unsigned char ** [WORLDSIZE]; 

... Sie neu zugewiesen nur frame zu einem anderen zugewiesenen Array. Der alte Zeiger frame ist verschwunden, und Sie haben gerade die metrische Tonne Speicher freigegeben, die Sie ursprünglich zugewiesen haben.

Derselbe Fehler mit Ihrem anderen, colormix Array.

Lektion, die daraus gelernt werden: Der beste Weg, um Bugs zu beheben, ist, sie nie an erster Stelle zu machen. Hätten Sie C++ - Container verwendet, die alle Speicherzuweisungen für Sie richtig handhaben, wie std::vector, wäre dies nie passiert. Richtiges Verwenden der vollen Ressourcen der C++ - Bibliothek - Container, Iteratoren, Algorithmen - machen es logisch unmöglich, dass viele häufige Programmierfehler passieren.

+0

Ah, ich habe die Schleife kopiert, die ich benutzt habe, um die Arrays zu erstellen, um sie zu löschen und habe vergessen die 'new []' s ... und Dann bemerkte ich nicht, dass ich das zwei Tage lang getan hatte. Deshalb vermeide ich C++ generell ... Danke! – Schilcote

+0

Hätten Sie 'std :: vector' benutzt, hätten Sie nichts kopieren müssen, da der Vektor die Deallocaiton für Sie erledigt hätte und der Bug nie passiert wäre. Genau das meinte ich. –

+0

@Schilcote: 'new []' ist eine Fehlfunktion von C++, die sowieso niemand benutzen sollte. Sie verwenden Standard-Container-Klassen, die solche Fehler verhindern. Intern verwenden diese Containerklassen das Placement new. –