std :: map导致"堆栈溢出"在低记忆的情况下

时间:2014-06-09 08:26:27

标签: c++ stl stack-overflow stdmap

此应用程序正在Windows XP中的VS2010中以C ++开发。

当计算机在物理内存上运行时非常低(并且因为它是我们的测试用例而禁用了页面文件),这行代码:

std::map<UINT, std::vector<void *>> MyMap;

导致&#34;堆栈溢出&#34; malloc.c中的错误

'return HeapAlloc(_crtheap, 0, size ? size : 1);'

MyApp.exe中0x7c90e8e5处的未处理异常:0xC00000FD:堆栈溢出。

此调用是从应用程序的一个线程进行的。 如果内存不足是错误,它应该抛出bad_alloc

有人可以在这里建议可能的原因。

编辑:

这就是实际堆栈的样子

ntdll.dll!7c90e8e5()    

[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 

ntdll.dll!7c9100d3()    

MyApp.exe!_heap_alloc_base(unsigned int size=72)  Line 55   C

MyApp.exe!_heap_alloc_dbg_impl(unsigned int nSize=36, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x0af3f0e4)  Line 431 + 0x9 bytes   C++

MyApp.exe!_nh_malloc_dbg_impl(unsigned int nSize=36, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0, int * errno_tmp=0x0af3f0e4)  Line 239 + 0x19 bytes C++

MyApp.exe!_nh_malloc_dbg(unsigned int nSize=36, int nhFlag=0, int nBlockUse=1, const char * szFileName=0x00000000, int nLine=0)  Line 302 + 0x1d bytes  C++

MyApp.exe!malloc(unsigned int nSize=36)  Line 56 + 0x15 bytes   C++

MyApp.exe!operator new(unsigned int size=36)  Line 59 + 0x9 bytes   C++

MyApp.exe!std::_Allocate<std::_Tree_nod<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >::_Node>(unsigned int _Count=1, std::_Tree_nod<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >::_Node * __formal=0x00000000)  Line 36 + 0x15 bytes C++

MyApp.exe!std::allocator<std::_Tree_nod<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >::_Node>::allocate(unsigned int _Count=1)  Line 187 + 0xb bytes C++

MyApp.exe!std::_Tree_val<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >::_Tree_val<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >(const std::less<unsigned int> & _Parg=less, std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > > _Al={...})  Line 544 + 0xd bytes C++

MyApp.exe!std::_Tree<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >::_Tree<std::_Tmap_traits<unsigned int,std::vector<void *,std::allocator<void *> >,std::less<unsigned int>,std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > >,0> >(const std::less<unsigned int> & _Parg=less, const std::allocator<std::pair<unsigned int const ,std::vector<void *,std::allocator<void *> > > > & _Al={...})  Line 699 C++

3 个答案:

答案 0 :(得分:3)

  #define STACKSIZE (1024*896)

这肯定是个问题,程序的主线程正在绊倒页面保护异常的边缘,启动堆栈溢出异常。在Windows上,HeapAlloc()将因两个基本原因而失败。到目前为止,您已经假设的常见问题是,地址空间不足是正常的故障模式。

但Windows也提供了强有力的保证,任何虚拟内存分配都始终映射到RAM。当内存过度提交且没有可用于修复页面错误的RAM时,它没有类似于"out of memory killer"的任何内容,随机中止进程。始终提交分配,并保证RAM页面可以被丢弃或交换到磁盘。如果您在没有分页文件的情况下运行Windows,那么很难提供该保证。提交失败显然是可能的。

接下来发生的事情很难猜测,你的堆栈跟踪没有给出任何提示。请务必配置符号服务器,以便获取ntdll.dll的符号。但显然,HeapAlloc()将遵循不同的路径,而不是通常在提交失败时的路径。我猜某种调试器探测器,真的不知道。嵌套更深,需要更多堆栈空间。这足以使堆栈保护页面跳闸并触发堆栈溢出异常。

不确定如果解决这个问题确实很重要,你的程序无论如何都是死的。从提交失败中恢复几乎是不可能的。它完全随机,受其他进程中的VM分配影响。在没有页面文件的情况下运行需要大量RAM,并且非常小心控制允许在机器上运行的进程。 RAM比你在软件中可能做的更便宜。

答案 1 :(得分:2)

低记忆并不总是意味着bad_alloc。调用堆栈也会消耗内存。如果系统无法为另一个函数调用创建新堆栈或达到callstack数量限制,则会发生堆栈溢出错误。

我认为HeapAlloc是CRT(基本上是C函数调用)的一部分。 new运算符会引发bad_alloc,而不是HeapAlloc

答案 2 :(得分:0)

我意识到这不是特定于std :: map的问题。当内存不足并且不存在分页文件时,简单的应用程序也会导致堆栈溢出。这是因为Windows为堆栈的每个线程保留了一定量的内存。但是,它不一定能够提交内存。在这种情况下,“堆栈溢出”发生。

#include <stdio.h>
#include <conio.h>

#define STACKSIZE (1024*896)

void FunctionWithBigStack()
{
    char stack[STACKSIZE];
    printf("\nAllocated %d KB stack successfully", STACKSIZE/1024);
    stack[STACKSIZE-1] = 123; // Let's use 'stack' array so that optimizer won't discard it while compiling
}

int _tmain(int argc, _TCHAR* argv[])
{
    printf("\nThrough another application, try make all the memory full and then press a key to call a function that has %d KB stack", STACKSIZE/1024);
    _getch();
    FunctionWithBigStack();
    return 0;
}

此应用程序在正常内存条件下运行完美,但如果我们在等待击键时使内存已满 ,我们可以看到FunctionWithBigStack崩溃并出现“堆栈溢出”