2016-11-19 41 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++的一个错误特性,无论如何都不应该使用它。你使用防止这种错误的标准容器类。在内部,这些容器类使用新的位置。 –