Strange std::bad_alloc
据我所知,可以引发std :: bad_alloc的原因有三个:
该进程请求的内存超出了可服务的范围
地址空间过于分散,无法满足对大块连续内存的请求
堆管理数据结构已损坏
我们有运行到std :: bad_alloc的代码,但上述原因似乎都不适用。数据结构是存储为顶点的std :: list的图形,其中每个顶点再次存储作为其一部分的边的std :: list以及一定数量的连续数据。
对于小图(<= 100'000个顶点),该程序运行得非常好,而不管每个顶点的数据段有多大(我们可以毫无问题地分配总计40 GB的内存)。但是,如果顶点数量增加,即使在仅使用8 GB内存的实例上,也会引发std :: bad_alloc异常。
由于在较大的块中分配更多的内存时没有问题,因此应排除上述原因1.和2.。在某些部分中,我们以容易出错的方式来处理指针,因此有可能破坏堆数据结构。但是,当在较小的实例上运行时,valgrind的memcheck报告我们的代码无缺陷,因此原因似乎也不大可能(在抛出实例时,valgrind本身会耗尽内存,因此我们无法直接检查这种情况)。
关于此行为的原因还有什么想法,或者我们可能会进行哪些测试以进一步解决问题?
操作系统:Fedora 19
构建系统:使用gcc 4.8.2的cmake
-
不要忘记,内存管理器通常会将16-20字节添加到计算中的每个分配中。
-
从技术上讲,只能抛出bad_alloc的原因只有一个:分配内存失败。
-
在malloc方面实现您自己的新运算符,链接到合适的调试malloc库,启动gdb并存储肘部润滑脂。
-
您可能会看到签名的尺寸
-
OS /构建系统?
-
@pmr或代码中未定义的行为。
-
您的大图可能有循环吗?您的顶点有多大?我认为这是64位可执行文件?您正在使用哪个库实现?顶点的构造函数是否进行其他分配?难道其中之一会失控吗?您是否尝试过任何分配跟踪工具?
-
@BillyONeal:报告的内存占用量是htop向我报告的内容,因此不涉及任何计算。
-
@ n.m .:关于调试malloc库的任何建议?另外,如果我按照您的建议去做,我会发生什么?
-
@DieterLcking:我将std :: size_t用于所有尺寸类型。另外,取决于输入,bad_alloc会在代码中的不同位置抛出,这表明它确实是分配问题,而不是代码中的错误。
-
@AdrianMcCarthy:不,该图是一棵树。顶点包含边的std :: list,三个指针,四个长度<= 3的指针/整数的std :: vector以及大小可变的double字段。后者的大小范围可以从单个数字到几百万个数字,并且bad_alloc出现在数据字段大小的两个极端上(尽管对于较小的数据字段,树需要更大)。 std库的实现是GNU ISO C ++库,但是我无法弄清楚哪个版本(如何获得该版本的任何帮助?)。正如我所说,我尝试了Valgrinds memcheck。
-
dmalloc是这样的一个库。您还可以通过包装系统malloc来实现自己的功能。然后,您可以在操作符new即将引发异常时在其内部放置一个断点。当遇到严重问题时,请运行堆检查以确保堆未损坏,然后分析消耗的内存量及其碎片。
-
感谢您的提示。我尝试使用dmalloc,所以我下载,编译,运行测试以及出现繁荣,分段错误。在gdb下运行它暗示它陷入了无限递归中。我已经阅读了一些有关dmalloc的内容,但我不确定它是否可以比valgrinds memcheck做的更多。因此,我不确定使dmalloc工作是否值得。
-
鉴于我不知道OS /库如何管理堆,我如何自己检查堆?另外,我在可执行文件退出之前就停止了它,并查看了/ proc / [pid] / maps中的内存映射。我惊讶地发现可执行文件不仅为堆分配了一个内存区域,还为34000个不同的内存区域分配了内存。在本地计算机上而不是在计算服务器上做同样的事情,我只有一个大堆。我的感觉告诉我,这可能会引起麻烦,但是我对内存管理了解得很少,无法
-
使用dmalloc,可以启用检查堆调试令牌。默认情况下,这将导致它在每次分配时遍历并验证内部堆数据结构。这可能很慢,因此可以选择每N个分配周期执行一次。
-
如果要包装系统malloc,则当您收到分配N个字节的请求时,请从系统malloc中获取N + 2*sizeof(void*) + 2 * k大约k(也许k == 8或k == 16)。使用两个指针来构建分配区域的双向链接列表。使用额外的2*k字节在开头和结尾填充区域。在填充的空间上写一些"签名"(您选择的位模式)。现在,您可以随时浏览链表并检查签名是否完整。如果不是这样,则您的某个地方存在缓冲区溢出或类似错误。
-
栅栏后检查也由memcheck完成,因此,我不必尝试任何新方法。 仅堆一致性检查将很有用,但此刻我不想修复另一个损坏的程序。 不过还是谢谢您的帮助! 多亏了您,我才知道malloc实现是可以互换的,一旦我找到时间,我可能会尝试另一种实现,而不是编译器的默认实现,然后查看问题是否仍然存在。
-
也许是GPU驱动程序问题?
-
几乎不。 我不使用GPU,甚至不知道我使用的系统上是否存在任何东西。 这是一台没有(据我所知)任何图形前端的计算服务器。
我无法对您的信息发表评论,因此将其回复。
在Kaldi(与您的系统和gcc相同)上使用OpenFST时遇到了相同的问题。 我没有跟踪此问题的确切来源,但似乎内核3.12才是此问题。 我启动了其中一个备份内核(3.11系列之一),问题消失了。
您可以使用:
1
| yum list --showduplicates kernel |
查找可用的3.11内核。
编辑:
看来,此错误已在内核3.12.11-201和3.13+中修复
资料来源:Bugzilla
-
我们在具有3.10.11内核的另一台机器上运行我们的代码,它起作用了! 非常感谢您的提示,我们可能永远不会想到它可能是内核错误!
-
很高兴我帮助了我,我也花了一些时间到达那里;)