首页 文章

C 抛出的对象代码 std::bad_alloc

提问于
浏览
-5

我正在编写以下程序,我得到 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);
    }
}

我发现这个错误意味着我的内存不足。我想首先询问我的 List 是否存储在堆中然后我为什么会收到此错误。第二个堆最大大小是多少?

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

2 回答

  • 2

    您正在分配 160000 个A,其中包含 5000 int,通常大小约为 4 个字节,因此您分配的是 160000 * 5000 * 4 个字节,其中/1024 = 3.125.000 kibiBytes 和/1024 = 3.051,7578125 Mebibytes 所以大约 3 个 GB,接近上限,32-bit 进程可以得到什么,我认为,即使在运行 x64 窗口时,你使用默认的 x86 设置编译它,这意味着它将在 Windows 中以 32 位兼容模式运行。添加你存储在效率最低的std容器中的 160000 指针的开销,加上分页的东西,加上可能添加的填充,你内存不足。

    要回到原来的问题:

    • 该列表放在“堆栈”i.e 上。具有自动存储持续时间(更正确的术语),这意味着只有它的家庭数据(例如指向第一个项目的指针,一个指向最后一个项目和它的大小),但不包含它包含的 items/nodes,即使它已经包含,它不包含大的东西,i.e。你的A只是指向它们的指针A* s,反过来,就像在任何std容器中一样,除了std::array存储在堆上,i.e。 “动态存储持续时间”,但它们的大小与它们指向的 5000 英寸不相上下。当您使用 new 分配时,您的A永远不会被清除,直到您通过删除调用。 C 与 Java 非常不同。而你的 Java 代码可能是一个 64 位进程,它知道 VM 做了什么,因为它看到你将来不会使用它们。

    所以,如果你想让你的A在“堆栈”i.e 上。自动存储持续时间,你可以使用std::array<A,160000>(这是一个更好的 A [11]版本),但我打赌你会崩溃堆叠这样的大小。 (在大多数操作系统上,每个线程可以获得大约 2MB 的堆栈,但它可以低得多,并且您的调用树也需要放置)

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

    • 在 C 标准中没有这样明确的限制,根据§3.7.4ISO/IEC 14882:2014,new要么获得请求的数量或更多,要么失败,所以它取决于你的运行时 i.e。实现意味着操作系统和编译器,但一般来说,你可以获得操作系统给你的程度,正如我所说的那样 3-4GB 为 x86/32bit 进程。否则它可以更多,或者在嵌入式应用程序的情况下,非常少于 0(根本没有动态分配)。
  • 0

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

相关问题