Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。
尽管有上述特性,为什么不鼓励使用alloca() ?
Alloca()在堆栈上分配内存,而不是像malloc()那样在堆上分配内存。因此,当我从例程返回时,内存被释放。这实际上解决了动态分配内存的问题。通过malloc()释放分配的内存是一个非常令人头痛的问题,如果以某种方式错过释放会导致各种内存问题。
尽管有上述特性,为什么不鼓励使用alloca() ?
当前回答
每个人都已经指出了堆栈溢出潜在的未定义行为,但我应该提到的是,Windows环境有一个很好的机制来捕捉这种情况,使用结构化异常(SEH)和保护页面。由于堆栈只在需要时增长,因此这些保护页驻留在未分配的区域。如果你对它们进行分配(通过溢出堆栈),就会抛出一个异常。
您可以捕获这个SEH异常并调用_resetstkoflw来重置堆栈并继续您的快乐之路。这并不理想,但这是另一种机制,至少可以在事情发生时知道哪里出了问题。*nix可能有类似的东西,但我不知道。
我建议通过包装alloca并在内部跟踪它来限制您的最大分配大小。如果你真的很认真,你可以在函数的顶部设置一些作用域哨兵来跟踪函数作用域中的任何分配,并检查它与项目允许的最大数量是否一致。
此外,除了不允许内存泄漏之外,alloca也不会导致内存碎片,这是非常重要的。我不认为alloca是不好的做法,如果你明智地使用它,这基本上适用于所有事情。: -)
其他回答
Alloca()很好,很有效……但它也被深深打破了。
broken scope behavior (function scope instead of block scope) use inconsistant with malloc (alloca()-ted pointer shouldn't be freed, henceforth you have to track where you pointers are coming from to free() only those you got with malloc()) bad behavior when you also use inlining (scope sometimes goes to the caller function depending if callee is inlined or not). no stack boundary check undefined behavior in case of failure (does not return NULL like malloc... and what does failure means as it does not check stack boundaries anyway...) not ansi standard
在大多数情况下,您可以使用局部变量和主要大小来替换它。如果它用于大型对象,将它们放在堆上通常是一个更安全的想法。
如果你真的需要它,你可以使用VLA(在c++中没有VLA,太糟糕了)。在作用域行为和一致性方面,它们比alloca()要好得多。在我看来,VLA是一种正确的分配。
当然,使用所需空间的主要部分的本地结构或数组仍然更好,如果没有这样的主要堆分配,则使用普通malloc()可能是明智的。 我没有看到你真的真的需要alloca()或VLA的用例。
这个“老”问题有很多有趣的答案,甚至一些相对较新的答案,但我没有找到任何提到这个....
当正确和小心使用时,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(),请注意不要在循环中使用它,并确保您的函数不能内联,如果它有任何可能在另一个函数的循环中调用。
答案就在手册页中(至少在Linux上):
返回值 函数的作用是:返回一个指向对象开头的指针 分配空间。如果 分配的原因 堆栈溢出,程序行为未定义。
这并不是说它永远不应该被使用。我工作的一个OSS项目广泛使用它,只要你不滥用它(分配巨大的值),它是好的。一旦超过了“几百字节”的标记,就应该转而使用malloc和friends。您可能仍然会遇到分配失败,但至少您会得到一些失败的指示,而不是仅仅耗尽堆栈。
实际上,alloca并不保证使用堆栈。 事实上,gcc-2.95的alloca实现使用malloc本身从堆中分配内存。此外,这个实现是有bug的,它可能会导致内存泄漏和一些意想不到的行为,如果你在一个块内调用它进一步使用goto。并不是说您永远都不应该使用它,但有时alloca会导致比它从me中释放更多的开销。
进程只有有限的堆栈空间可用——远远小于malloc()可用的内存量。
通过使用alloca(),您将极大地增加获得Stack Overflow错误的机会(如果幸运的话,或者如果运气不好,则会出现莫名其妙的崩溃)。