嵌套的QVector指针内存处理

时间:2018-01-09 12:11:34

标签: c++ memory-leaks windows-7 qt5

我继承了一个实质性的Qt5项目,其中累积的内存泄漏正成为一个严重的问题。 (是的,应该很少容忍内存泄漏,但实际预算和时间限制......)。

此GUI将图像数据读取到体素类的对象中,以图形方式显示。数据来自文件或缓冲区(如果实时获取)并存储为嵌套qvector,即:

QVector < QVector <Voxel *> > cVoxel;

从文件中读取图片时,使用cVoxel初始化QVector.resize(0)

cVoxel.resize(0);

打开保存到文件的图像时,会创建一个本地Voxel指针,并将其推送到cVoxel的末尾,每个像素一次,因此循环遍历所有行和列:< / em>的

for (iRow = 0; iRow < nRows; ++iRow)
{
   for (iCol = 0; iCol < nCols; ++iCol)
   {
      Voxel *v = new Voxel;
      cVoxel[iRow].push_back(v);
      // Code for reading data into cVoxel removed here
      ...
   }
}

由于以下有用的评论,通过在我的CTOR中嵌套cVoxel QVector的嵌套,我现在已经在Windows任务管理器中看到内存使用减少方面取得了一些成功。沿着:

for (iRow = 0; iRow < nRows; iRow++)
{
    for (iCol = 0; iCol < nCols; iCol++)
    {
        delete cVoxel[iRow][iCol];
    }
}

理想情况下,重大改写是最佳解决方案。但在现实世界中,我将不得不尝试修复更大的泄漏并希望这足够,直到有足够的资源可用于更理想的解决方案。

  • 我已经看过Voxel本身的内存泄漏,但那里没有什么明显的。
  • 我的研究表明,查看Windows任务管理器的内存消耗并不完全可靠(Win7不是实时操作系统......),但是如果打开文件会将应用程序内存消耗从16M增加到81.5M ,如果cVoxel中分配的内存成功释放,肯定会有某些内存减少?如果我继续打开和关闭图像,应用程序的内存消耗会在类似步骤中不断增加。关闭任何/所有打开的图像后,它永远不会减少。
  • 现在,没有尝试释放任何分配给({使用新运算符)的内存到cVoxel。我已经尝试了一些方法(并阅读以了解更多),但到目前为止运气不错。
  • QVector非常善于处理它自己的内存处理,但我坚持使用这个嵌套QVector设置,只需依靠QVector的squeeze(),resize()或类似的只会泄漏内存(已经是项目中其他变量的情况..我通过Visual Leak Detector运行项目,所以我知道哪些是严重的罪魁祸首,哪些是小鱼)

----编辑----

为下面的凌乱广告评论道歉,但这肯定有助于我减少内存泄漏(有希望在适当的时候完成停止......)。

我已经在线编辑了(希望)使这篇文章更加清晰,并删除了我最好的案例工作,因为它对内存泄漏没有影响。上面的重大改动是(2)斜体的简短段落。

我还需要调查@richardcitter(sp?)多态相关的建议。

--- EDIT3 ---

删除了Edit2,单独发布了(新)问题here

另外,我非常有信心下面的答案应该可以解决这个问题 - 我只需要弄清楚如何使用qvector.resize()或找到解决方法。

2 个答案:

答案 0 :(得分:1)

在评论中格式化代码很困难,所以我将其添加为答案,即使它可能无法解决您的问题。无论如何,它的评论也相当长。

要解决未定义的行为并正确确保您不需要进行任何额外分配,您可以预先分配向量中的元素数量。当你打电话给resize(0)时,你已经这样做了,但不是设置你真正需要的大小,而是将大小设为零,你将向量设为空。

我会建议这样的事情:

首先使用Richard Critten建议的std::unique_ptr

QVector < QVector < std::unique_ptr <Voxel> > > cVoxel;

如果Qt有自己独特的指针类型,你可以改用它。

然后在创建时使用resize设置向量的实际大小:

cVoxel.resize(nRows);

然后您可以在矢量中使用普通索引。设置内部向量的大小:

for (iRow = 0; iRow < nRows; ++iRow)
{
   cVoxel[iRow].resize(nCols);  // Resize to the number of columns

   for (iCol = 0; iCol < nCols; ++iCol)
   {
      cVoxel[iRow][iCol].reset(new Voxel);  // Create the actual Voxel object

      // Code for reading data into cVoxel here
      ...
   }
}

由于您使用std::unique_ptr(或等效的Qt),一旦对象被破坏,std::unique_ptr对象管理的内存将自动释放。因此,当cVoxel向量超出范围或以其他方式被破坏时,不再有内存泄漏,您的Voxel对象也将被破坏。

答案 1 :(得分:0)

@SomeProgrammerDude:你让我9/10迈向解决方案。我不知道是否应该编辑你的答案或使用它,所以主持人请相应地进行编辑。

a connected SO post所述,我最终决定反对智能指针。上面的解决方案(对我来说)引入了试图引用已删除函数的编译器的问题。否则它是正确的,有一些修改:

QVector < QVector <Voxel *> > cVoxel;

初​​始化:

cVoxel.resize(0);

记忆分配:

{
   for (int i = 0; i < rows; ++i)
   {
      cVoxel.push_back( QVector <Voxel *> () );
      for (int j = 0 ; j < cols ; ++j)
      {
         Voxel *v = new Voxel;
         cVoxel[i].push_back(v);
      }
   }
}

最后DTOR释放内存:

   int iRow, iCol;
   for (iRow = 0; iRow < rows; iRow++)
   {
      for (iCol = 0; iCol < cols; iCol++)
      {
           delete cVoxel[iRow][iCol];
      }
   }