【问题标题】:seqmentation fault at memory allocation内存分配中的分段错误
【发布时间】:2013-03-21 21:10:22
【问题描述】:

在启动时,我的应用程序将在大约 %50 的时间内崩溃,并在以下代码行出现分段错误:

float** temp = new float*[map_size];

map_size 的值为 513。

调试模式下永远不会出现这种错误。该应用程序现在相当大,有 10,000 行代码,并且有多个线程在运行,所以我怀疑发布任何其他代码是否有用。 (我不知道该发什么)

由于这行代码相当简单,我猜我的错误在其他地方。我最好的猜测是,我的程序在其他地方超出了分配的内存,然后当我偶尔尝试分配更多内存时,它会发生冲突并导致错误。这是一种可能的情况吗?

什么样的行为会导致内存分配出现分段错误?以及如何缩小代码中发生这种情况的范围?

【问题讨论】:

  • map_size 的期望值是多少?
  • 有数百种可能发生的“场景”,您真的希望我们列出所有这些吗?你试过什么了?使用任何一种可用的调试器?
  • 如果您运行 Mac 或 Linux,valgrind 工具可能对您有用。它会检测到这种内存错误并告诉你有问题的代码行在哪里。
  • 如果你绝对肯定是那一行导致了崩溃,唯一的问题可能是map_size
  • map_size 绝对不是问题。如果我用预期值“513”替换它。崩溃仍然发生。

标签: c++ memory-management segmentation-fault


【解决方案1】:

调用内存分配函数的崩溃几乎总是由于堆损坏。

想想内存分配函数是如何工作的。它首先检查以前释放的块的列表,看看是否有一个合适的大小,如果没有找到,它会向操作系统请求一个新的块。

如果其他代码通过写入超出其他一些动态分配对象的范围而破坏了堆的内部指针,那么当::operator new 使用的内存分配函数尝试遍历堆时,它将使用野指针并崩溃。

崩溃发生在这里,但内存损坏发生得更早,并且可以在您的程序中使用动态分配的对象的任何地方。它甚至不必是发生分配或释放的地方。

检查您的编译器是否提供“malloc 调试”,它会向围绕动态分配的堆元数据添加额外的金丝雀字段,以检测超出范围的写入。 Electric Fence(免费!)之类的东西也可以提供帮助,通过安排一个无法访问的内存页面将元数据与每个对象分开,因此 MMU 捕获边界错误。或者类似于 Rational Purify 的运行时边界检查器(真的非常昂贵)。

【讨论】:

  • 很可能是正确的,在 Windows 上,我会直接通过 AppVerifier 运行该程序以捕获早期的损坏。我不确定其他平台上有哪些工具可用于此类事情。
  • @Benj:使用了哪个特定的 AppVerifier 选项?有一个专门用于堆调试的,对吧?
  • 谢谢!我会检查代码中的其他地方,看看是否能找到有问题的代码。
  • @Ben:是的,页面堆选项就是其中之一。我相信它将每个分配都放在它自己的页面中,然后用保护模式填充你不使用的内容。如果您误入任何不属于您分配的内存,您的程序会立即崩溃。
  • @Benj:守卫模式实际上不会立即导致崩溃,但它确实缩小了很多范围。这就是我提到的金丝雀领域。 Electric Fence 更进一步,实际上保留了额外的地址空间页面,相当于VirtualProtect 来阻止读取、写入和执行。这确实在损坏第一次发生的地方使程序崩溃。 Electric Fence 的选项允许您将对象与页面的顶部或底部对齐,以捕捉对象的正面或背面的溢出。
猜你喜欢
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
  • 2020-03-29
  • 2020-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多