Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么必须在堆上malloc大型数据结构?_C_Stack_Malloc_Stack Overflow_Heap Memory - Fatal编程技术网

为什么必须在堆上malloc大型数据结构?

为什么必须在堆上malloc大型数据结构?,c,stack,malloc,stack-overflow,heap-memory,C,Stack,Malloc,Stack Overflow,Heap Memory,我记得我说过堆栈内存地址是如何增长的,堆是如何增长的,但是它们占用了相同的内存条。如果是这样的话,为什么一些大型数据结构会导致堆栈溢出,但在堆上却很好?首先,忽略您听到的历史上的过度简化,有一个基本原因,您需要对大型对象使用malloc,而不是自动(“堆栈”)存储:只有malloc有一个接口,它可以通过该接口报告内存不可用。如果您使用char foo[100000000]输入函数在它的主体中,在基于堆栈的实际实现中,堆栈指针将调整100000000,但在这一点上,谁知道它是指向可用作堆栈一部分的

我记得我说过堆栈内存地址是如何增长的,堆是如何增长的,但是它们占用了相同的内存条。如果是这样的话,为什么一些大型数据结构会导致堆栈溢出,但在堆上却很好?

首先,忽略您听到的历史上的过度简化,有一个基本原因,您需要对大型对象使用
malloc
,而不是自动(“堆栈”)存储:只有
malloc
有一个接口,它可以通过该接口报告内存不可用。如果您使用
char foo[100000000]输入函数在它的主体中,在基于堆栈的实际实现中,堆栈指针将调整100000000,但在这一点上,谁知道它是指向可用作堆栈一部分的空闲内存,还是指向其他无关内存的顶部。一些实现(GCC的
-fstack clash protection
)将一次调整一个页面,并探测每个页面以在第一个保护页面上产生错误,从而使程序崩溃,而不是破坏无关内存,但这也不是一个理想的结果。无论何时出现故障,您都需要一个报告和处理故障的渠道

现在,关于为什么历史上“堆增长,堆栈下降”的解释是错误的:

  • 它只在只有一个堆栈时工作。在多线程程序中,每个线程有一个堆栈。如果你想把它们都放在一个位置,这样它们就可以以巨大的利润增长,那么你就很难在32位内存空间中创建任何线程。在64位系统中,这是可能的,只是因为空间太大,但有问题(而且大多数64位系统实际上并没有64个可用的地址位)

  • “堆”和“堆栈”不是内存空间中唯一的东西,“堆”甚至不是一个有意义的概念。是的,历史上的
    malloc
    实现对大多数分配使用了不断增长的固定“堆范围”,但通常会豁免非常大的分配,而不是对每个分配执行单独的
    mmap
    munmap
    。但更重要的是,其他东西也存在于这个空间中——你的程序的可执行代码、可执行代码和共享库的数据段等等。在现代系统上,这些东西的放置位置是随机的,以减轻程序错误的后果。这意味着它们可以被放置在您想要的“堆的顶部”和“堆栈的底部”之间的任何位置,从而限制它们可以连续增长的距离


  • 首先,忽略您所听到的历史上的过分简化,您需要对大型对象使用
    malloc
    而不是自动(“堆栈”)存储的一个根本原因是:只有
    malloc
    有一个接口,它可以通过该接口报告内存不可用。如果您使用
    char foo[100000000]输入函数在它的主体中,在基于堆栈的实际实现中,堆栈指针将调整100000000,但在这一点上,谁知道它是指向可用作堆栈一部分的空闲内存,还是指向其他无关内存的顶部。一些实现(GCC的
    -fstack clash protection
    )将一次调整一个页面,并探测每个页面以在第一个保护页面上产生错误,从而使程序崩溃,而不是破坏无关内存,但这也不是一个理想的结果。无论何时出现故障,您都需要一个报告和处理故障的渠道

    现在,关于为什么历史上“堆增长,堆栈下降”的解释是错误的:

  • 它只在只有一个堆栈时工作。在多线程程序中,每个线程有一个堆栈。如果你想把它们都放在一个位置,这样它们就可以以巨大的利润增长,那么你就很难在32位内存空间中创建任何线程。在64位系统中,这是可能的,只是因为空间太大,但有问题(而且大多数64位系统实际上并没有64个可用的地址位)

  • “堆”和“堆栈”不是内存空间中唯一的东西,“堆”甚至不是一个有意义的概念。是的,历史上的
    malloc
    实现对大多数分配使用了不断增长的固定“堆范围”,但通常会豁免非常大的分配,而不是对每个分配执行单独的
    mmap
    munmap
    。但更重要的是,其他东西也存在于这个空间中——你的程序的可执行代码、可执行代码和共享库的数据段等等。在现代系统上,这些东西的放置位置是随机的,以减轻程序错误的后果。这意味着它们可以被放置在您想要的“堆的顶部”和“堆栈的底部”之间的任何位置,从而限制它们可以连续增长的距离


  • stck传统上是有限的,而堆可以利用整个内存。@Devolus,这与OPs(correct)的观察相矛盾,OPs(correct)观察到传统上堆栈内存地址增长,堆增长。所以他们可以在这两者之间的任何地方相遇。@PaulOgilvie,为什么这会是一个矛盾呢?堆栈空间不足时会发生堆栈溢出,但这是确定的。它与可用内存无关,因为这取决于体系结构。有限的堆栈大小是操作系统的功能,而不是语言或底层硬件(通常)。这样做的动机是,如果某个进程出现流氓行为(比如写得不好的递归调用)并威胁到整个系统的稳定性,那么就确保没有一个进程会占用所有可用内存。当然,如果你在堆上发疯,同样的事情也会发生,stck传统上是有限的,而堆可以利用整个内存。@Devolus,这与t