【问题标题】:Memory leakage when creating object in a loop在循环中创建对象时内存泄漏
【发布时间】:2014-02-26 17:35:30
【问题描述】:

我是 C++ 和内存管理的新手。我有一个代码是建立一个由顶点(每个约 100 个字节)和边缘(每个约 50 个字节)类型的对象组成的图。当图形很小时,我的代码可以正常工作,但是对于具有 ~ 3M 顶点和 ~ 10M 边的真实数据,我得到运行时错误:使用“new”时的 std::bad_alloc(并不总是使用相同的 new )。

根据我收集到的信息,这是我的程序中的内存泄漏导致新内存分配失败的影响。我的问题是我分配内存的方式出了什么问题,更重要的是我该如何解决它。这大致是我所做的: 在图形类构造函数中,我为类顶点的对象创建数组存储库:

 graph:graph()
{
   // vertexes is a class varaible
   vertexes = new vertex *[MAX_AR_LEN];// where MAX_AR_LEN = 3M
}

然后我调用这样的函数来迭代构建 obj 顶点并将它们分配给数组。

 void graph::buildVertexes()
{
    for(int i=0; i<v_num; i++)
       vertexes[i] = new vertex(strName);
}

然后我完成其他任务,最后在程序结束之前我有一个析构函数,它显式删除图形对象

 graph:~graph()
{
  delete[] vertexes; 
  vertexes = 0;
}

泄漏发生在哪里。我正在创建很多对象,但据我所知,没有任何可以删除且未删除的对象。 我已经处理了一个多星期了,但运气并不好。非常感谢您的帮助!

EDIT(解决问题后): 谢谢大家的帮助。回顾过去,根据我提供的信息,很难确定发生了什么。我解决了这些问题,这是我拿走的非常明显的要点;如此明显,可能不值得分享,但无论如何它们都在这里:

  1. 在处理需要同时存在于内存中的大量对象时,在编码之前使用您的最佳估计来找到您需要的最小内存。就我而言,即使没有泄漏,我也会几乎耗尽内存。我只是需要更好地估计内存使用情况来解决这个问题。
  2. 在开发代码时,经常使用 vld.h(或其他替代方法)有助于检查您的设计是否没有内存泄漏。最后执行此操作可能要复杂得多,即使您发现泄漏,也可能更难修复。
  3. 假设您完成了所有这些操作,并且您希望有足够的内存来运行代码,但是当您的系统上似乎有大量可用内存时,您会收到 std::bad_alloc 运行时错误。您可能正在为 32 位平台编译,切换到 64 位将允许从可用内存中分配更多内存(对于 visual studio: )。
  4. 这里很多人建议使用向量而不是数组是一种有用的方法,可以避免常见的泄漏路径(以及其他便利),但是假设您有内存泄漏并且您有数组。由于数组不一定是泄漏的原因(显然),切换到向量可能无法为您服务。看看数组删除虽然是一个好的开始。以下是我收集的关于如何正确删除指向对象的指针数组的内容:
//Let's say we have
objType **objAr = new objType[ aNum];  
for(int i=0; i<objNum; i++)
{
    ObjAr[i] = new objType();
}
// to delete:
for(int i=0; i<objNum; i++)
{
    delete objAr[i];
}
// If instead of array of pointers we had just
// an array of objects loop wasn't needed
delete [] objAr; 
objAr = 0;

具有讽刺意味的是,我的代码中的一个泄漏源是不正确地删除了指向对象的指针向量。对于向量,我需要先逐个删除元素,然后执行 vec.clear()。只是做后者会导致内存泄漏。

【问题讨论】:

  • 你没有delete vertexes[i];,只有顶点数组。这就是为什么您应该绝对改用std::vector&lt;vertex&gt;
  • 添加到@H2CO3 的评论,使用vector 是否也可以使vertexes 足够大以容纳真正需要的元素数量,而不是一些硬编码的最大大小(可能太大了)。
  • 感谢您的回复!下次我肯定会尝试向量,但这次需要对我希望避免的事情进行大量重新洗牌。我知道数组更容易出现问题,但不会固有地导致泄漏。没有用向量重新编码,我能做些什么来用数组挽救代码吗?
  • @user3208953 您至少可以将vertexes 声明为vertex* vertexes[MAX_AR_LEN],然后您就不需要动态分配该数组(尽管您仍然需要动态分配vertexs。
  • 计算您正在使用多少个news,以及您正在使用多少个deletes。你很快就会发现它们没有加起来......

标签: c++ memory-management


【解决方案1】:

看看你使用了多少次new。您使用它一次来分配指针数组(new vertex *[MAX_AR_LEN]),然后使用它v_num 次来分配每个顶点。为避免内存泄漏,您必须使用 delete 的次数与使用 new 的次数相同,以便释放分配的所有内容。

您将不得不遍历您的指针数组并在每个指针上执行delete vertexes[i]

但是,如果您使用了std::vector&lt;vertex&gt;,则不必处理这种手动内存分配,并且可以避免此类问题。

注意“顶点”的复数形式是“顶点”

【讨论】:

  • 感谢您的评论(以及拼写更正,我知道它看起来不正确)。我的理解是 new 被称为 v_num 次,而 delete[] (而不是 delete)调用数组中所有元素的析构函数。无论如何,在我调用 delete[] 之前,运行就中断了。再次感谢您的回复。下次我会尝试将矢量作为我的第一选择。希望我可以挽救代码,而不需要像将东西放入向量中那样进行重大改组(我已经过期了)再次感谢!
  • @user3208953 delete[] 不会为数组中的所有元素调用析构函数。它所做的是释放数组本身。由于您手动分配了每个vertex,因此您必须将它们全部释放。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
  • 2014-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多