【问题标题】:Debugging an apparent memory-issue in a C++-program在 C++ 程序中调试明显的内存问题
【发布时间】:2013-02-23 01:56:10
【问题描述】:

我正在使用其他人创建的程序。我在编码方面有相当多的经验,但在 C++ 编码方面没有那么多经验,所以我在这里做了很多“边做边学”。 所以这个程序看起来很稳定,我开始了我的工作,主要包括对程序的小部分进行小修改。 最近做了一些性能优化,看起来也很稳定,但是前两天我改了一些东西,一直在崩溃。所以我恢复了我的更改,但仍然出现崩溃。 我开始使用带有激活页面堆的应用程序验证器和全局标志,并检查所有与堆相关的内容以找出导致这些问题的原因。因此,从那时起,调试器总是因“std::bad_alloc”错误而崩溃。 因为我使用的是 SVN,所以我还检查了我得到的代码的第一个版本 - 我也在那里遇到了 bad_alloc-crash。

现在我的问题是:我可以绝对肯定,启用应用程序验证程序的这个 bad_alloc 崩溃是程序内部错误的指标吗?使用应用程序验证程序时,程序本身会使用大量内存,大约 1-1.1gb,但不再使用了。总系统内存最多使用了 80-90%,所以我不认为有可用空间太少导致的实际分配问题。 你怎么看?

【问题讨论】:

  • std::bad_alloc 也可以通过将NULL 传递给std::string 引起(以及其他几个潜在原因)。它不仅仅在耗尽内存时引发。
  • 你能告诉我们任何代码吗?
  • @Borealid: std::bad_alloc can also be caused by passing NULL to an std::string :根据cplusplus.com,如果指针为NULL,那么它会导致未定义的行为。阅读标准,我看到字符串构造函数:“要求:s 不应是空指针”,这对我来说是“未定义的行为”的味道......
  • Application Verifier 修改堆,以便当页面被释放时,它们被特别标记并且不能被重用。对于具有大量内存需求或大量分配/释放的应用程序,应用程序验证程序通常会导致应用程序耗尽内存,这种方式不一定表明应用程序本身存在问题。
  • 几乎不涉及任何字符串,因此这不太可能导致问题。而且实际上不可能向您展示任何代码,因为它太多了 - 而且由于崩溃是在某个明显随机的位置引起的,因此没有任何代码可以帮助您。 @Chad:谢谢-我认为可能存在这样的问题。实际上,该程序必须进行许多分配/解除分配。事实上,这就是我正在努力加快速度的方法,即内存池。

标签: c++ bad-alloc


【解决方案1】:

不,您不能绝对确定任意 C++ 程序中的任何内容,因为您的程序可能包含未定义的行为(事实上,几乎可以肯定,尽管它可能与手头的问题无关)。也就是说,std::bad_alloc 的常见原因是无法分配内存。

使用std::set_new_handler 设置自定义new_handler,并在其中放置断点。如果触发了断点,那么您的问题几乎可以肯定是无法分配内存(此时程序的状态可能有助于调试您的问题)。

【讨论】:

  • "使用 std::set_new_handler 设置自定义 new_handler" 我怎么没想到?... o.O? ... +1
【解决方案2】:

默认情况下,x86 的 Windows 上的 32 位进程是 limited to 2GB of address space(完整地址空间的下半部分)。

如果您的程序执行大量分配和解除分配,或者如果您的程序需要大量连续分配,那么是的,当您的程序仅使用 1.1GB 工作集时,很有可能没有足够的连续地址空间来提供服务分配。

(几年前我参与了一个大型项目,该项目受到地址空间的严格限制。对于我们来说,使用 1.2 到 1.4 GB 的工作集“内存不足”是很常见的。)

页堆肯定会让这个问题变得更加严重,因为大多数分配都比通常情况下要大得多。

【讨论】:

  • 好的,通常程序需要大约 200MB 的内存 - 是否正确,如果所有分配/释放都正确完成并且页堆被停用,如果不需要的话应该没有问题单个大分配? (如果我做对了,频繁的分配/解除分配会导致“到处”分配,这意味着如果需要,分配的块之间可能没有足够的空间来分配一个大块 - 对吗?)
  • @MrWayne 我强烈建议您使用 vmmap (technet.microsoft.com/en-us/sysinternals/dd535533.aspx) 分析您的软件。它可以让您非常准确地看到您真正拥有多少可用内存。对于某些受地址空间严格限制的大型项目来说,这是天赐之物。
【解决方案3】:

您应该研究当二进制文件因 std::bad_alloc 崩溃时收到的堆栈。

通常,这应该是因为new 无法分配内存。通过堆栈,您应该能够知道请求了多少内存,如果这对您来说很奇怪(例如“请分配 3Go!”),那么您就知道您的错误在哪里。

阅读您的问题时不清楚,但是如果您的意思是该进程使用了​​高达 80%-90% 的可用虚拟内存,那么您的内存可能是碎片化的,而您正在尝试分配一个太大的对象,无法容纳剩余的空闲小内存块...... 因此,尽管您的进程仍有内存可玩,但分配错误。

在您的代码中进行搜索以查看您的代码的某些部分是否手动抛出 bad_alloc 也是一个好主意。

【讨论】:

  • 关于已用内存:程序通常使用大约200MB的RAM(我不太了解虚拟和非虚拟内存,200MB是任务管理器中显示的数量),与App Verifier 启用它大约为 1.1GB,并且与所有其他程序一起,任务管理器表示正在使用 80-90% 的物理内存。如何在崩溃时检查调用堆栈?我正在使用 Eclipse,它所做的只是告诉我有一个错误的分配异常导致崩溃。这不是断点!
  • 您通常可以在任何平台上生成核心转储。为你的平台谷歌,获取核心转储(在 Windows 上,它通常是某种“.dmp”文件,在 Linux 上,它更像是一个“核心”文件),然后用你的调试器“打开它”。跨度>
猜你喜欢
  • 2014-08-06
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 2018-01-26
  • 2023-03-25
  • 2013-10-13
相关资源
最近更新 更多