查找bad_alloc原因的调试策略
我的程序中有一个相当严重的错误 - 偶尔调用 new() 会抛出 bad_alloc。
从我可以找到的关于 bad_alloc 的文档来看,它似乎是由于以下原因而抛出的:
当计算机内存不足时(这绝对不会发生,我有 4GB 的 RAM,当使用少于 5MB 时,程序会抛出 bad_alloc (在任务管理器中检查)后台没有任何严重的运行)。
如果内存变得过于碎片化而无法分配新块(同样,这不太可能 - 我分配的最大大小的块约为 1KB,并且在崩溃发生之前分配的次数不会超过 100 次)。
根据这些描述,我实际上没有任何地方可以抛出 bad_alloc 。
然而,我正在运行的应用程序运行多个线程,这可能会导致这一问题。通过在单个线程上测试所有对象,一切似乎都运行顺利。我能想到的唯一另一件事可能是由于同时在多个地方调用 new() 引起的某种竞争条件,但我尝试添加互斥体来防止这种行为没有效果。
因为该程序有几百行,而且我不知道问题实际上出在哪里,所以我不确定要发布哪些代码片段(如果有)。相反,我想知道是否有任何工具可以帮助我测试此类事情,或者是否有任何通用策略可以帮助我解决这个问题。
我正在使用 Microsoft Visual Studio 2008,并使用 Poco 进行线程处理。
I have a fairly serious bug in my program - occasional calls to new() throw a bad_alloc.
From the documentation I can find on bad_alloc, it seems to be thrown for these reasons:
When the computer runs out of memory (which definitely isn't happening, I have 4GB of RAM, program throws bad_alloc when using less than 5MB (checked in taskmanager) with nothing serious running in the background).
If the memory becomes too fragmented to allocate new blocks (which, again, is unlikely - the largest sized block I ever allocate would be about 1KB, and that doesn't get done more than 100 times before the crash occurs).
Based on these descriptions, I don't really have anywhere in which a bad_alloc could be thrown.
However, the application I am running runs more than one thread, which could possibly be contributing to the problem. By testing all of the objects on a single thread, everything seems to be working smoothly. The only other thing that I can think of that is going on here could be some kind of race-condition caused by calling new() in more than one place at the same time, but I've tried adding mutexes to prevent that behaviour to no effect.
Because the program is several hundred lines and I have no idea where the problem actually lies, I'm not sure of what, if any, code snippets to post. Instead, I was wondering if there were any tools that will help me test for this kind of thing, or if there are any general strategies that can help me with this problem.
I'm using Microsoft Visual Studio 2008, with Poco for threading.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当你有一个错误覆盖了堆用来管理它用来分配的内存池的指针时,也可能会抛出 bad_alloc 。
最常见的原因是您写入的内容超出了分配的内存块的末尾(或在开始之前,但这种情况不太常见)。几乎同样常见的是在释放内存块后对其进行写入。这称为堆损坏。
另外,我应该指出,Windows 中的 32 位进程最多有 2GB 地址空间(对于大型地址感知程序为 3GB)。这与您安装了多少 RAM 无关,内存是虚拟的,并且即使您只有 1GB RAM,分配也不会失败,直到您用完地址空间。
这是关于 C++ 中内存损坏的一个很好的讨论 http://www.eventhelix.com/RealtimeMantra /Basics/debugging_software_crashes_2.htm
bad_alloc can also be thrown when you have a bug that is overwriting the pointers that the heap uses to manage the pool of memory that it uses to allocate from.
The most common cause of that is that you are writing past the end of an allocated block of memory, (or before the start, but that's less common). Almost as common is writing to a memory block after it has been freed. This is called heap corruption.
Also, I should note, a 32 bit process in Windows has at most 2GB of address space (3GB for large-address-aware programs). This is regardless of how much RAM you have installed, the memory is virtual, and allocations don't fail until you run out of address space, even if you only have 1GB of RAM.
Here is a good discussion of memory corruption in C++ http://www.eventhelix.com/RealtimeMantra/Basics/debugging_software_crashes_2.htm
另一个可能的问题是,虽然您提到该程序使用的空间少于 5MB,但您没有提到它试图分配多少空间。您可能会遇到一些竞争条件,从而破坏用于确定分配大小的值,并且可能会尝试分配 37TB 或类似的废话。
我认为不太可能,但值得检查。
Another possible problem is that, while you mention that the program is using less than 5MB, you don't mention how much space it's trying to allocate. You could have some race condition that's corrupting the value that you use to determine the allocation size, and it could be trying to allocate 37TB or somesuch nonsense.
Not particularly likely, I suppose, but worth checking.
需要澄清的是:
Windows 中的每个进程都获得 4GB 虚拟内存,其中 2GB 用于用户空间,其余用于内核空间。 4GB RAM 不会用于虚拟内存,而是用于物理内存。
在2GB内存中,所有EXE、DLL都被加载,几乎没有1.6 - 1.7GB可用于内存分配。在此内存中,如果没有连续的内存可供分配,则内存分配失败。
Few clarifications:
Every process in windows gets 4GB virtual memory, out of which 2GB is for user space and remaining for kernel space. The 4GB of RAM won't contribute to the virtual memory but it is for physical memory.
In the 2GB memory, all EXE, DLL gets loaded and hardly 1.6 - 1.7GB available for memory allocation. In this memory if there is no contiguous memory for allocation then the memory allocation fails.
bad_alloc 也可以由其他代码抛出。
我见过它被设计用于 STL 容器的限制内存池使用。当达到大小限制时,它会抛出 bad_alloc 并且软件只需处理它。
bad_alloc can be thrown by other code as well.
I've seen it used by a limiting memory pool designed for use with STL containers. When the size limit was hit, it threw bad_alloc and the software just had to handle it.
实际上我以前也遇到过这个问题,通过清理和重建项目解决了这个问题。当你有奇怪的行为时总是值得一试(除非它是一个需要几个小时才能编译的大型项目)。
I've actually had this problem before and it was fixed by cleaning and rebuilding the project. Always worth a try when you have weird behaviour (unless it is a huge project that takes hours to compile).
调试此问题的策略是在调试器中设置捕获点。在 gdb 中,只要程序抛出异常,就会说“catch throw”来要求调试器停止。如果程序在正常业务过程中抛出并捕获大量异常,您可以将其改进为仅捕获 std::bad_alloc。调试器将在生成 std::bad_alloc 的分配函数内停止,允许您四处查看。在这种情况下,您很快就会发现请求的字节数不是您所期望的。
A strategy for debugging this would be to set a catchpoint in the debugger. In gdb one would say “catch throw” to ask the debugger you stop whenever the program throws an exception. You can refine that to catch only std::bad_alloc if the program throws and catches lots of exceptions in its normal course of business. The debugger will stop inside whichever allocation function generates std::bad_alloc, allowing you to poke around. In this case, you would quickly learn that number of bytes requested is not what you expect.