【问题标题】:Does delete[] really work in C++?delete[] 真的在 C++ 中有效吗?
【发布时间】:2014-11-09 08:52:01
【问题描述】:

我有一个每次运行时使用 0.5 MB 内存的函数。于是我决定一边看Windows任务管理器一边一步步调查。我注意到这些行之后:

int **banned;
banned=new int*[vertices];
for(i=0;i<vertices;i++)
    banned[i]=new int[k_colors];

它使用 0.5 MB 内存。然后我决定在return这一行之前删除它:

for(i=0;i<vertices;i++)
   for(j=0;j<k_colors;j++)
       delete []banned[j];
   delete[]banned;

使用函数开头的内存为 8.5 MB。分配之后变成了9MB,但是删除部分之后还是9MB。我在整个程序中执行了这个函数 1000 次。然后它被操作系统杀死。知道为什么会这样吗?我该如何解决?

编辑:这里是main() 部分:

int main()
{
    srand(time(0));
    input();
    initialize();
    for(int i = 0; i < MAX_GENERATION; i++)
    {
        parents = selection(TS);
        population = cross_over(parents, PC);
        mutation(PM);
        elite=tabu_search(population);
        elitism(); //270 MB memory using each time.

    }
fclose(pFile);
return 0;
}

上面,elitism()函数的第一行是分配部分,最后一行是delete部分。

【问题讨论】:

  • delete[] 不会将内存归还给操作系统
  • 是否将内存返回给操作系统并不重要。重要的是,内存以这样一种方式返回,即未来的分配可以重新使用该内存。无论是通过将其返回给操作系统还是在内部将其标记为未使用都无关紧要。无论哪种方式,你都是对的,重复运行相同的函数不应该导致内存使用的重复增加,这似乎表明某处存在泄漏。
  • 你不是 delete 在这段代码中你是 newing,顺便说一句
  • @WhoCares - 那是因为您的代码错误。您循环一种分配方式,然后以完全不同的方式解除分配。换句话说,你迷失了方向,没有正确地倒车。
  • @WhoCares - MattMcNabb 给你的答案解决了这个问题。

标签: c++ memory-management delete-operator


【解决方案1】:

要正确使用delete[],您应该删除新创建的相同内容:

for(i=0;i<vertices;i++)
    delete [] banned[i];

delete[] banned;

您的“进程被杀死”可能是因为您的原始代码导致了大量未定义的行为,多次删除同一个指针等等。

此版本可能会也可能不会向操作系统释放内存;这是您的编译器/库和操作系统做出的决定。在某些系统上,内存似乎仍分配给您的进程,但如果另一个进程需要,操作系统将能够声明它。

如果你一遍又一遍地调用同一个函数,它不应该积累内存;之前的delete'd 块可以接听new 呼叫。

【讨论】:

  • 你好。这在 Windows 中工作得很好,但在 linux 中它返回 seg。过错。你知道为什么吗?
  • 您在未发布的代码中有一个错误。尝试调试您的程序。在 linux 中使用 gdb 和 valgrind。
  • 现在我通过 valgrind 调试了它。事情是这样的;我删除了你给我的代码。它在linux中运行良好。有了这个形状,我用 valgrind 运行它,它给出了一个关于 fscanf() 的错误。但是,它们是程序的非常不同的部分。我的意思是fscanf()delete 部分。而且,如果我再次添加,valgrind 没有告诉我任何关于你给我的代码的信息。它仍然在说fscanf()。你认为它们有某种关联吗?
  • 顺便说一句,我将它与valgrind --leak-check=yesline 一起使用。
  • 开始一个新问题fscanf与这个无关。听起来你有堆损坏。确保发布 MCVE,否则人们只是在猜测。
【解决方案2】:

当您在应用程序中分配内存时,C++ 运行时会要求操作系统提供“更多内存”。假设您将再次分配更多内存,“如果没有释放大量内存 - 坚持下去”。换句话说,“任务管理器”和其他此类工具对于准确了解应用程序中实际分配了多少内存并不理想。

但是,delete [] 确实适用于所有商业级发布的编译器环境。

您的代码中的问题是您正在删除未分配的内容。

您为每个vertices 调用delete [] 并为整个数组调用一次,匹配您的new 调用。 [你有new的每个地方,都应该有完全相同的delete——同样的次数,同样的指针]

也有可能你正在“碎片化”记忆——例如这样的事情

size_t s = 100;
for(;;)
{
    int *p = new int[s];

    ...
    delete [] p; 
    s += 10;
}

因此,释放的内存对于下一次分配来说“太小”了。

当然,这整个混乱可以通过使用来避免

vector< vector <int> > banned(vertices);
for(i=0;i<vertices;i++)
   banned[i].resize(k_colors);

现在使用的内存会自动清理。

【讨论】:

  • 如果“工作”是指“如果不引入无尽的可怕错误并且在各方面都严格低于其他方法的情况下无法使用”,那么是的。不过,这是对“工作”的一个相当奇怪的定义。
  • 呃,那是不同的点。大多数容器类型的基础是 newdelete [虽然通常包装在分配器类中,但这只是顶部的糖]
猜你喜欢
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多