C ++抛出std :: bad_alloc的对象代码列表

时间:2018-12-12 09:00:09

标签: c++ bad-alloc

我正在编写以下程序,并且得到了std :: bad_alloc异常。

class A{
public:
    int arr[5000];

    A() {
        for ( int i = 0; i < 5000; i++ ) {
            arr[i] = 0;
        }
    }
};

int main() {
    int cnt=0;
    std::list<A*> mylist;
    A *aref= NULL;
    for(int i=0;i<160000;i++){
        aref = new A();
        mylist.push_back(aref);
    }
}

我发现此错误意味着我内存不足。我想先问一下我的列表是否存储在堆中,然后为什么会出现此错误。其次,堆的最大大小是多少?

我使用-Xmx8000m在Java中运行相同的程序,并且该程序正常终止。我的RAM是16GB(如果需要的话)

2 个答案:

答案 0 :(得分:2)

您要分配160000个A,其中5000个int,通常大小约为4个字节,因此您要分配160000 * 5000 * 4个字节,即/ 1024 = 3.125.000 kibiBytes和/ 1024 = 3.051,7578125 Mebibytes,大约3 GB(接近上限),这是32位进程可以获得的上限,我假设即使在运行x64 Windows时,也使用默认编译x86设置,这意味着它将在Windows中以32位兼容模式运行。加上存储在效率最低的std容器中的160000个指针的开销,再加上分页`东西的开销,再加上可能添加的填充,就会耗尽内存。

回到您的原始问题:

  1. 列表位于“堆栈”上,即具有自动存储期限(更正确的术语),这意味着仅其家庭数据(例如,指向第一项的指针,指向最后一项的指针及其大小) ,但不包含其中的项目/节点,即使包含,也不包含大的东西,即您的A,而只是指向它们的指针A*,反过来,如除std之外的任何std::array容器都存储在堆上,即“动态存储持续时间”,但与它们指向的5000个int相比,大小没有任何区别。当您分配有new时,您的A永远不会被清理,直到您进行删除呼叫。 C ++与Java非常不同。而且您的Java代码可能以64位进程运行,该进程知道VM所做的事情,因为它看到您将来不会使用它们。

因此,如果您希望A位于“堆栈”上,即自动存储持续时间,则可以使用std::array<A,160000>(这是A [160000]的更好版本),但是我敢打赌这样的尺寸会使您的堆栈崩溃。 (在大多数操作系统上,每个线程大约有2MB的堆栈,但是它可能要低得多,并且调用树也需要放置)

如果您希望A位于“堆”上,即具有动态存储持续时间,即在列表中,请使用std::list<A>而不是std::list<A*>并删除new完全表达。但是,由于多种原因,最好的默认容器是std::vector<A>,它将默认存储在一大堆“堆”内存中。

  1. 根据ISO / IEC 14882:2014的§3.7.4,C ++标准中没有这样的明确限制,new可以让您或更高获得所需的金额,或者它会失败,因此取决于您的运行时,即实现的含义,即操作系统和编译器,但总的来说,您可以获得的操作系统所能提供的一切,正如我所说的,x86 / 32bit进程大约为3-4GB。否则可能会更多,或者对于嵌入式应用程序,可能会少得多,直到0(根本没有动态分配)。

答案 1 :(得分:0)

std::list被实现为双链表,节点分配在堆上。 std::list<A*> mylist对象本身具有自动存储持续时间,它具有较小的sizeof,但是您用mylist.push_back(aref)添加到它的每个元素除了您new A之外还将执行堆分配手动进行。