嵌套 QVector 指针内存处理

问题描述 投票:0回答:2

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

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

QVector < QVector <Voxel *> > cVoxel;

从文件中读取图像时,使用

cVoxel
初始化
QVector.resize(0)

cVoxel.resize(0);

打开保存到文件的图像时,会创建本地

Voxel
指针并将其推送到
cVoxel
的末尾,每个像素一次,因此循环遍历所有行和列:

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中分配的内存成功释放,肯定会有
    some
    内存减少吗?如果我继续打开和关闭图像,应用程序的内存消耗会以类似的步骤不断增加。关闭任何/所有打开的图像后它永远不会减少。
  • 现在,没有尝试释放(使用 new 运算符)分配给
    cVoxel
    的任何内存。我尝试了几种方法(并阅读以了解更多信息),但到目前为止运气不佳。
  • QVector 非常擅长处理它自己的内存处理,但我坚持使用这个嵌套 QVector 设置,并且简单地依赖 QVector 的挤压(),调整大小()或类似的只会泄漏内存(这已经是这种情况项目中的其他变量..我已经通过视觉泄漏检测器运行了该项目,所以我知道哪些是严重的罪魁祸首,哪些是小鱼)

----编辑----

对下面乱七八糟的评论表示歉意,但这确实帮助我减少了内存泄漏(希望在适当的时候完全停止......)。

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

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

---编辑3---

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

另外,我非常有信心下面的答案应该可以解决这个问题 - 我只需要弄清楚如何使用

qvector.resize()
或找到解决方法。

c++ memory-leaks windows-7 qt5
2个回答
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
对象也将如此。


0
投票

@SomeProgrammerDude:你给了我 9/10 的解决方案。

正如连接的SO帖子中所述,我最终决定不使用智能指针。上面的解决方案(对我来说)引入了编译器尝试引用已删除函数的问题。否则,经过一些修改后它是正确的:

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];
      }
   }
© www.soinside.com 2019 - 2024. All rights reserved.