何时最好使用堆栈而不是堆,反之亦然? 我已经阅读了一些关于堆栈与堆的其他问题,但它们似乎更关注堆/栈做什么,而不是为什么要使用它们。
对我来说,由于堆栈指针移动快(只需移动堆栈指针,而不是在堆中寻找空闲空间),而且在使用完分配的内存后无需手动释放它,因此几乎总是优先选择堆栈分配。唯一我能想到需要使用堆分配的原因是,如果您想在函数中创建一个对象,然后在该函数范围之外使用它,因为从函数返回后,堆栈分配的内存会自动被释放。
除了我不知道的在堆分配而不是堆栈分配时使用的其他原因之外,还有吗?
有几个原因:
malloc
/calloc
到 free
)进行最灵活的控制;如果没有灵活的对象生命周期,诸如二叉树和链表这样有用的数据结构将几乎无法编写。
其中最重要的是第1点。一旦涉及到任何形式的并发或 IPC,第1点就无处不在。即使是非平凡的单线程应用程序也很难在没有堆分配的情况下设计。这几乎相当于在 C/C++ 中伪造一个函数式语言。
我想创建一个字符串。我可以在堆上或栈上创建它。我们来尝试一下:
char *heap = malloc(14);
if(heap == NULL)
{
// bad things happened!
}
strcat(heap, "Hello, world!");
并且对于堆栈:
char stack[] = "Hello, world!";
现在我有这两个字符串分别在它们的位置上。稍后,我想让它们变长:
char *tmp = realloc(heap, 20);
if(tmp == NULL)
{
// bad things happened!
}
heap = tmp;
memmove(heap + 13, heap + 7);
memcpy(heap + 7, "cruel ", 6);
并且对于堆栈:
// umm... What?
这只是其中一个好处,其他人已经提到了其他好处,但这是一个相当不错的好处。使用堆内存,我们至少可以尝试将我们分配的空间变大。对于栈而言,我们只能使用固定大小的空间。如果我们想要更多的空间来增长,我们必须一开始就声明所有需要的空间,而我们都知道这是多么麻烦:
char username[MAX_BUF_SIZE];
在使用堆的时候,最明显的理由是当你调用一个函数并需要返回长度未知的内容时。有时候调用者可能会传递内存块和大小给函数,但在其他情况下这是不可行的,特别是如果返回的内容很复杂(例如,一组带有指针的不同对象集合等)。
在很多情况下,大小限制是一个巨大的瓶颈。堆栈通常以低兆字节甚至千字节为单位测量(这是针对堆栈上的所有内容),而所有现代PC都允许您使用几个GB的堆。因此,如果您将使用大量数据,则绝对需要堆。
堆栈变量(通常称为“自动变量”)最适合用于您希望始终保持相同且始终很小的内容。
int x;
char foo[32];
所有的堆栈分配都是在编译时固定的。
堆分配最好的理由是你不能总是知道需要多少空间。通常只有在程序运行时才能确定。你可能有一个限制的想法,但你只想使用所需的确切空间。
如果你必须读取一个文件,它可能是从1k到50mb的任何大小,你不会这样做:
int readdata ( FILE * f ) {
char inputdata[50*1024*1025];
...
return x;
}
这将尝试在堆栈上分配50MB的空间,但通常会失败,因为堆栈通常限制在256k以内。