【问题标题】:C++ Vector catch resize Memory LeakC++ 向量捕获调整大小内存泄漏
【发布时间】:2014-05-15 12:48:13
【问题描述】:

我正在尝试保存一个充满指向 Circle 对象的指针的向量。 有时 bad_alloc 捕获有效,但有时无效,然后我收到错误消息:

此应用程序已请求运行时以不寻常的方式终止它。 请联系应用程序的支持团队了解更多信息。”

也许向量数组不能分配更多的内存......但是 bad_alloc 没有抓住它。

Circle *ptr;
vector<Circle*> ptrarray;

try{
  for (long long i = 0; i < 80000000; i++) {
    ptr = new Circle(1,i);
    ptrarray.push_back(ptr);
  }
}catch(bad_alloc &ba){
  cout << "Memory Leak" << endl;
}

如果有人可以帮助我,那就太好了;) 提前致谢

【问题讨论】:

  • 请添加编译器/操作系统标签。如果系统使用延迟分配,它会解释这一点。发布一个完整的程序也很有用,因此其他人可以重现(并检查您未显示的代码中没有错误)。
  • 如果您真的内存不足,可能甚至没有足够的资源来运行您的处理程序(例如,cout 内部的某处可能存在动态分配,可能会触发第二次未捕获的抛出),在这种情况下,程序将只是 abort() 并且您将收到您引用的消息。
  • @dlf 体内有什么需要创建的吗?可能会隐式转换为std::string,但我不这么认为。我认为就处理程序的范围而言,一切都是静态的。如果没有足够的内存用于处理机制本身,那就太奇怪了……如果需要任何额外的东西。
  • @luk32 我不知道;我们看到的代码中没有任何内容,但我不知道&lt;&lt; 在内部做什么,也不知道bad_alloc 的构造函数。
  • @dlf 好吧,即使... IMO 应该在try 的开头保留一些内存,以确保这样一个简单的处理程序不会出现内存问题。我觉得相当危险。即使在其他异常的情况下,如果您处于 OOM 的边缘,您也可以通过这么简单的事情来炸毁。

标签: c++ vector alloc bad-alloc


【解决方案1】:

许多操作系统将允许进程请求比其支持的虚拟内存更多的虚拟地址(名义上可用内存),前提是进程可能不会实际访问所有页面。众所周知,这允许稀疏数组在此类系统上实用。但是,当您访问每个页面时,CPU 会产生一个中断,并且操作系统必须找到物理内存来支持该页面(如果已配置,也交换到非 RAM 交换磁盘/文件等) - 当所有选项都用尽时(或者有时当您操作系统危险地接近极限,并且某些保护进程决定最好杀死某些进程而不是让已知的关键进程开始失败),您可能会收到像您观察到的错误。最终,在 C++ 级别无法控制这一点。您可以快速保留和写入所有页面,因此在进行所有处理之前您可能会失败,但即便如此,您也可能会在内存极度不足的情况下被终止。


另外,如果您按值存储它们,您可以将更多的圆圈放入内存中。也就是说,如果sizeof(Circle) &gt; sizeof(Circle*) 和碎片限制了你,你可能不会,在这种情况下你可以试试std::deque。无论如何:

try
{
    std::vector<Circle> array;
    array.reserve(80000000);
    for (long long i = 0; i < 80000000; i++) {
        array.emplace_back(1, i);
}
catch (const bad_alloc& ba)
{
    std::cerr << "Memory Exhaustion\n";
}

【讨论】:

  • 哇,这样的做法不会使试图抓住bad_alloc 的感觉失效吗?这听起来很危险,因为您可以执行一些具有永久性后果并在以后崩溃的语句。不可能实现任何事务性的。还是我错了?
  • 这样的做法确实使std::bad_alloc的概念失效。这就是现代计算机时代的生活。 Konrad Rudolph 在这个答案stackoverflow.com/a/9456758/774499 中的建议很准确:一般来说,你不能也不应该尝试回应这个错误。
  • 哇,所以总的来说,在运行 OOM 的情况下,没有什么可以确保安全。糟糕,RAM 很便宜。
  • @luk32:RAM 很便宜,而用于交换的磁盘要便宜很多,所以虚拟内存可以非常大,但是如果程序访问足够多的分配的虚拟内存,它们经常会被阻塞在页面错误上,整个系统开始爬行。最好的办法是配置系统以适当地优先处理进程,例如对于 Linux read this
【解决方案2】:

通过任务管理器监控您的进程内存 - 您可能会消耗该进程允许的所有内存(取决于您的起点和 Circle 的大小)。

如果您在 Win32 机器上,那么您有 ~2GB 的进程内存空间用于此操作

【讨论】:

  • 问题不在于内存不足,而在于没有发出或捕获适当的异常。
【解决方案3】:

首先,您如何确定唯一可能引发的异常是std::bad_alloc?我强烈建议您在 catch (const bad_alloc&amp;) 块之后添加一个 catch (...) 块,以验证您是否正确。当然,catch (...) 你不会知道抓到了什么,只知道不是@​​987654327@。

其次,如果您以某种方式触发了未定义的行为(例如,通过取消引用 NULL 指针),您不一定会得到异常; you won't necessarily get any behavior that makes sense according to the language rules.

第三,正如已经建议的on Linux you might be triggering the out of memory killer。这不是真正符合标准的行为,但它是您在现实生活中可能遇到的行为。

【讨论】:

    猜你喜欢
    • 2018-02-14
    • 1970-01-01
    • 2013-03-01
    • 2021-03-20
    • 2016-02-25
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    相关资源
    最近更新 更多