何时使用栈分配的数组,何时使用堆分配的数组?

4

有人告诉我不要使用堆栈分配的数组,因为堆栈是一种宝贵的资源。其他人建议我,只要数组相对较小,使用堆栈分配的数组是完全可以的。

我想要一个经验法则:什么情况下应该使用堆栈分配的数组?什么情况下应该使用堆分配的数组?


4
尽可能使用栈,必须使用堆。“栈是宝贵的资源”等同于废话。当然,在栈上分配多兆字节的结构不是明智之举,但那只是个特殊情况。 - Jon
可能是Malloc或普通数组定义?的重复问题。 - hmjd
1
我非常喜欢这个短语“尽量使用堆栈,必要时才使用堆”! - Rango
5个回答

3

尽管今天的RAM和虚拟内存具有巨大的容量,但是所有的内存都是有限制的。不过,与堆栈相比,它的限制相当大,堆栈在小型嵌入式系统上可能只有几kb,在PC上可能有几MB。

此外,还要考虑如何使用内存,以及用于什么目的。例如,如果您想从函数返回一个"数组",则它永远不应该在堆栈上。

通常情况下,如果可以的话,请尽量保持堆栈上的数组较小。如果您在堆栈上创建了一个有数千个条目的数组,您应该停下来思考一下它的用途。


缓冲区通常具有数千个条目,并且通常在堆栈上分配。当您说“数千个”时,您指的是几万或几十万? - richard
@richard 嗯,我见过大小为8192的char数组的代码,甚至达到32kb,但我个人认为超过8k可能有点太多了。 - Some programmer dude
这种观点基于什么?也就是说,为什么8 KiB太多,而不是其他限制,比如10 MiB或1 GiB? - Eric Postpischil
考虑到即使在现代PC上,堆栈通常只有几MiB,分配10MiB的堆栈空间会非常糟糕。保持堆栈空间小的主要原因是你永远不知道可用空间有多少,以及将来还需要多少空间。当然,你可以有一个占用几百KiB堆栈空间的数组,但如果该函数被递归调用几次,那么这个空间很快就会被耗尽。 - Some programmer dude

2

这要看你使用的平台。

如今,如果在流行的x64平台上工作,你不必太担心这个问题。

根据你使用的操作系统,你可以查看用户空间进程允许使用多少堆栈空间和堆空间。

例如,类UNIX系统有软限制和硬限制。有些可以增加,有些则不行。

总的来说,你通常不需要担心这些事情。当你需要知道时,通常你会紧密地与你所开发的平台联系在一起,了解所有这些细节。

希望我回答了你的问题。如果你想知道具体数值,请指定你的确切硬件、操作系统和用户权限。


1
这个问题的答案取决于上下文。例如,当您编写操作系统内核时,堆栈可能非常有限,分配超过一千字节的堆栈帧可能会导致问题。
在现代消费系统中,可用于堆栈的空间通常相当大。系统曾经存在的一个问题是地址空间有限,一旦为堆栈分配了地址,它就不能再向堆栈增长方向的下一个对象之外的虚拟内存或物理内存中增长,而不考虑地址空间中其他位置的可用性。在今天的地址空间中,这已经不是一个大问题了。
通常可以在堆栈帧中分配数兆字节的空间,并且这样做是便宜且容易的。但是,如果调用了许多分配大量空间的例程,或者调用了一个或几个分配大量空间的例程进行递归,则可能会出现问题,因为使用了太多空间,达到某个限制(例如地址空间或物理内存)。
当然,从堆中分配空间并不能缓解物理内存限制的问题。因此,只有消耗可用于堆栈的地址空间的问题与使用堆栈或堆的问题相关。

一个简单的测试方法是在你的main例程中插入大量堆栈空间的使用,以确定是否存在问题。如果你使用了额外的堆栈空间,并且你的应用程序在通常使用大量堆栈空间的负载下仍然正常运行,那么当你在main中删除这个人为保留时,你将有足够的余量。

更好的方法是计算你的程序可能使用的最大值,并将其与系统可用的堆栈空间进行比较。但是,在今天的软件中很少有这样的简单方法。

如果你遇到了堆栈空间限制,你的链接器或操作系统可能有选项可以提供更多的空间。


1

全局变量和静态变量的作用域将贯穿整个进程的生命周期。这些变量的内存将在进程启动时分配,并且只有在进程退出时才会释放。

但是局部变量(堆栈变量)仅在定义它的函数中具有作用域。当调用函数时,将分配内存,并且一旦控制从函数中退出,内存将被释放。

动态内存的主要目的是创建用户定义范围的变量。如果您想控制变量的作用域,则可以在一个函数中为变量x分配内存,然后将引用(地址)传递给您想要的许多函数,最后可以释放它。

因此,借助动态分配的内存,我们可以创建具有比局部变量更高作用域但比全局或静态变量更低的变量。

除此之外,如果大小非常大,最好使用动态内存,如果架构包含内存限制。


0

使用堆分配内存的好处是可以将其所有权传递给其他函数/结构。另一方面,栈为您提供了免费的内存管理,您不会忘记从栈中释放内存,而如果使用堆,则存在泄漏风险。

如果您仅为本地使用创建数组,则使用哪个大小的标准是很难确定的,但是当需要分配在堆上的内存超过几百字节时,就应该考虑使用堆。对于其他人来说,这个值可能更大或更小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接