Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。

尽管有上述特性,为什么不鼓励使用alloca() ?


当前回答

这个“老”问题有很多有趣的答案,甚至一些相对较新的答案,但我没有找到任何提到这个....

当正确和小心使用时,alloca()的一致使用 (可能是整个应用程序)来处理小的可变长度分配 (或C99 VLAs,如果可用)会导致整体堆栈降低 增长比使用超大的等效实现要快 固定长度的本地数组。因此,如果您仔细使用alloca(),它可能对您的堆栈有好处。

我在....上找到了这句话好吧,这句话是我编的。但真的,想想看....

@j_random_hacker在其他答案下面的评论中是非常正确的:避免使用alloca()来支持超大的本地数组并不能使你的程序更安全,免受堆栈溢出(除非你的编译器足够老,允许使用alloca()的函数内联,在这种情况下你应该升级,或者除非你在循环中使用alloca(),在这种情况下你应该……不要在循环内部使用alloca()。

I've worked on desktop/server environments and embedded systems. A lot of embedded systems don't use a heap at all (they don't even link in support for it), for reasons that include the perception that dynamically allocated memory is evil due to the risks of memory leaks on an application that never ever reboots for years at a time, or the more reasonable justification that dynamic memory is dangerous because it can't be known for certain that an application will never fragment its heap to the point of false memory exhaustion. So embedded programmers are left with few alternatives.

alloca()(或VLAs)可能是完成这项工作的合适工具。

I've seen time & time again where a programmer makes a stack-allocated buffer "big enough to handle any possible case". In a deeply nested call tree, repeated use of that (anti-?)pattern leads to exaggerated stack use. (Imagine a call tree 20 levels deep, where at each level for different reasons, the function blindly over-allocates a buffer of 1024 bytes "just to be safe" when generally it will only use 16 or less of them, and only in very rare cases may use more.) An alternative is to use alloca() or VLAs and allocate only as much stack space as your function needs, to avoid unnecessarily burdening the stack. Hopefully when one function in the call tree needs a larger-than-normal allocation, others in the call tree are still using their normal small allocations, and the overall application stack usage is significantly less than if every function blindly over-allocated a local buffer.

但是如果你选择使用alloca()…

根据本页上的其他答案,VLAs似乎应该是安全的(如果从循环中调用,它们不会复合堆栈分配),但如果您正在使用alloca(),请注意不要在循环中使用它,并确保您的函数不能内联,如果它有任何可能在另一个函数的循环中调用。

其他回答

alloca并不比变长数组(VLA)更糟糕,但它比在堆上分配更危险。

在x86上(最常见的是在ARM上),堆栈向下增长,这带来了一定的风险:如果你不小心写超出了用alloca分配的块(例如由于缓冲区溢出),那么你将覆盖你的函数的返回地址,因为它位于堆栈的“上面”,即在你分配的块之后。

这样做的后果是双重的:

程序将崩溃的壮观,它将不可能告诉为什么或哪里崩溃(堆栈将最有可能unwind到一个随机地址,由于覆盖的帧指针)。 它使缓冲区溢出的危险增加了许多倍,因为恶意用户可以制作一个特殊的有效负载,将其放在堆栈上,因此最终可以执行。

相反,如果你在堆上写超过一个块,你“只是”得到堆损坏。程序可能会意外终止,但会正确地展开堆栈,从而减少恶意代码执行的机会。

其他答案都是正确的。但是,如果使用alloca()要分配的对象相当小,我认为这是一种比使用malloc()或其他方法更快、更方便的好技术。

换句话说,alloca(0x00ffffff)是危险的,可能会导致溢出,就像char hugeArray[0x00ffffff];是多少。小心谨慎,通情达理,你会没事的。

正如在这篇新闻组帖子中提到的,有几个原因可以解释为什么使用alloca是困难和危险的:

并非所有编译器都支持alloca。 一些编译器对alloca的预期行为有不同的解释,因此即使在支持它的编译器之间也不能保证可移植性。 一些实现存在bug。

在我看来,alloca()在可用的情况下,应该仅以受约束的方式使用。就像“goto”的使用一样,相当多理智的人不仅对alloca()的使用非常反感,而且对它的存在也非常反感。

对于嵌入式使用,其中堆栈大小是已知的,并且可以通过对分配大小的约定和分析施加限制,并且编译器不能升级到支持C99+,使用alloca()是很好的,而且我已经知道使用它。

When available, VLAs may have some advantages over alloca(): The compiler can generate stack limit checks that will catch out-of-bounds access when array style access is used (I don't know if any compilers do this, but it can be done), and analysis of the code can determine whether the array access expressions are properly bounded. Note that, in some programming environments, such as automotive, medical equipment, and avionics, this analysis has to be done even for fixed size arrays, both automatic (on the stack) and static allocation (global or local).

在堆栈上存储数据和返回地址/帧指针的架构上(据我所知,这就是它们的全部),任何堆栈分配变量都可能是危险的,因为变量的地址可以被取走,未检查的输入值可能会允许各种各样的恶作剧。

在嵌入式领域,可移植性不是一个太大的问题,但是它是反对在严格控制的环境之外使用alloca()的一个很好的理由。

在嵌入式空间之外,我主要在日志记录和格式化函数中使用alloca()以提高效率,并在非递归词法扫描器中使用,其中临时结构(使用alloca()在标记化和分类期间创建,然后在函数返回之前填充持久对象(通过malloc()分配)。对较小的临时结构使用alloca()可以在分配持久对象时极大地减少碎片。

一个问题是,它不是标准的,尽管它得到了广泛的支持。在其他条件相同的情况下,我总是使用标准函数,而不是常用的编译器扩展。