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

C++ List of Objects code throwing std::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);
    }
}

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

我 运行 在 Java 中使用 -Xmx8000m 的相同程序,它正常终止。我的 RAM 是 16GB(如果这很重要)

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

回到你原来的问题:

  1. 列表放在"stack"即具有自动存储持续时间(更正确的术语),这意味着只有它的家庭数据(例如指向第一项的指针,以及指向最后一项的指针和它的大小),但不是它包含的 items/nodes,即使它包含,它也不包含大东西,即你的 A 只是指向它们 A* 的指针,反过来,就像在任何 std 容器中一样,除了 std::array 存储在堆上,即 "dynamic storage duration",但与它们指向的 5000 个整数相比,它在大小上没有任何意义。当你用 new 分配时,你的 A 永远不会被清理,直到你用 delete 调用。 C++ 与 Java 非常不同。你的 Java 代码可能 运行 作为一个 64 位进程,它知道 VM 做了什么,因为它看到你将来不会使用它们。

所以如果你想要你的 As 在 "stack" 上,即自动存储持续时间,你可以使用 std::array<A,160000>(这是 A[160000] 的更好版本) ,但我敢打赌你会崩溃你堆栈与这样的大小。 (在大多数操作系统上,每个线程大约有 2MB 的堆栈,但它可以低得多,而且你的调用树也需要放置)

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

  1. C++ 标准中没有这样的明确限制,根据 ISO/IEC 14882:2014 的 §3.7.4,new 要么让你得到请求的数量 或更多,否则它会失败,所以这取决于您的运行时间,即实现意味着操作系统和编译器,但通常您可以获得操作系统给您的尽可能多的东西,正如我据说 x86/32bit 进程大约需要 3-4GB。否则它可能更多,或者在嵌入式应用程序的情况下,非常少,直到 0(根本没有动态分配)。

std::list实现为双向链表,节点分配在堆上。 std::list<A*> mylist 对象本身有自动存储持续时间,它有一个小的 sizeof,但是你向它添加 mylist.push_back(aref) 的每个元素都会执行堆分配,除了你 new A手动做。