2016-11-19 43 views
1

我討厭做舊「這裏的一些代碼,這有什麼錯呢?」但我一直在調查這個問題好幾天沒有進展。這段代碼通常會在調試器關閉的情況下立即崩潰,但偶爾會有幾個小時的時間才能編譯並正確運行。使用gdb連接它可以工作,但每秒鐘以大約10 MB的速度泄漏內存,並在用完時最終崩潰。神祕的內存泄漏在C++中的文件輸出功能

這絕對是這個函數;當唯一的調用被註釋掉時,不會發生這樣的問題,並且調用它的次數減少會延遲內存不足的崩潰。

//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,scentmapsstd::unordered_map映射整數(一個SmellyObject的.ID性)WORLDSIZE雙打的X WORLDSIZE陣列。

+0

你已經使用'VECTOR',爲什麼你使用'新[]'和'刪除[]'代碼的某些部分? – krzaq

+0

你真的需要把這些指針弄亂_to指針__指針___嗎?爲什麼不使用「std :: vector」呢?好吧,這可能需要相當可怕的形式,比如'的std ::向量<性病::向量<性病::矢量 >>',但你不會需要爲元素分配內存,它會爲你節省大量的時間並且在調試時不會引起頭痛。 – ForceBru

+0

哎呀,當我看到'char *** frame'時,它會傷害我的眼睛...爲什麼你會使用3級間接?你不能只使用標準的C++容器嗎? – kebs

回答

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

您在函數的開始分配這個數組,並繼續分配所有的三個維度,吞噬了大量的內存。

然後,後來......

fout.close(); 

frame = new unsigned char ** [WORLDSIZE]; 

...你只是重新分配frame另一個分配的數組。舊的frame指針消失了,您剛剛泄漏了您最初分配的內存量。

同樣的bug與其他colormix陣列。

課從這個學習:修正錯誤的最好方法是永遠不會讓他們擺在首位。如果你一直在使用正確處理所有內存分配的C++容器,例如std::vector,那麼這種情況就不會發生。正確使用C++庫的全部資源 - 容器,迭代器和算法 - 使得許多常見的編程錯誤在邏輯上不可能發生。

+0

啊,我複製了我用來創建數組的循環來刪除它們,忘記取出'new []'...並且然後沒有注意到我這麼做了兩天。這就是爲什麼我通常完全避免使用C++ ...謝謝! – Schilcote

+0

如果你一直在使用'std :: vector',你不需要複製任何東西,因爲這個向量會爲你處理deallocaiton,並且這個bug永遠不會發生。這正是我的意思。 –

+0

@Schilcote:'new []'是C++的一個錯誤特性,無論如何都不應該使用它。你使用防止這種錯誤的標準容器類。在內部,這些容器類使用新的位置。 –