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

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


当前回答

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

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

其他回答

可悲的是,真正强大的alloca()在几乎强大的tcc中缺失了。Gcc确实有alloca()。

它播下了毁灭自己的种子。用return作为析构函数。 像malloc()一样,它在失败时返回一个无效的指针,这将在有MMU的现代系统上分段故障(希望重新启动那些没有MMU的系统)。 与自动变量不同,您可以在运行时指定大小。

它可以很好地用于递归。您可以使用静态变量来实现与尾递归类似的功能,并使用其他几个变量向每次迭代传递信息。

如果你推得太深,你肯定会出现段错误(如果你有一个MMU)。

注意,malloc()没有提供更多,因为当系统内存不足时,它会返回NULL(如果分配了NULL,也会出现段错误)。也就是说,你所能做的就是保释或试图以任何方式转让它。

要使用malloc(),我使用全局变量并将其赋值为NULL。如果指针不是NULL,我在使用malloc()之前释放它。

如果想复制任何现有数据,也可以使用realloc()作为一般情况。在使用realloc()之前,您需要检查指针,以确定是否要在realloc()之后复制或连接。

3.2.5.2 alloca的优点

我遇到的最令人难忘的错误之一是与一个使用alloca的内联函数有关。它在程序执行的随机点表现为堆栈溢出(因为它在堆栈上分配)。

在头文件中:

void DoSomething() {
   wchar_t* pStr = alloca(100);
   //......
}

在实现文件中:

void Process() {
   for (i = 0; i < 1000000; i++) {
     DoSomething();
   }
}

因此,发生的事情是编译器内联DoSomething函数,所有的堆栈分配都发生在Process()函数内部,从而使堆栈膨胀。在我的辩护中(我不是发现这个问题的人;当我无法修复它时,我不得不去和一个高级开发人员哭),它不是直接的分配,它是ATL字符串转换宏之一。

所以教训是-不要在你认为可能内联的函数中使用alloca。

实际上,alloca并不保证使用堆栈。 事实上,gcc-2.95的alloca实现使用malloc本身从堆中分配内存。此外,这个实现是有bug的,它可能会导致内存泄漏和一些意想不到的行为,如果你在一个块内调用它进一步使用goto。并不是说您永远都不应该使用它,但有时alloca会导致比它从me中释放更多的开销。

仍然不鼓励使用分配,为什么?

我没有看到这样的共识。很多强大的专业人士;一些缺点:

C99 provides variable length arrays, which would often be used preferentially as the notation's more consistent with fixed-length arrays and intuitive overall many systems have less overall memory/address-space available for the stack than they do for the heap, which makes the program slightly more susceptible to memory exhaustion (through stack overflow): this may be seen as a good or a bad thing - one of the reasons the stack doesn't automatically grow the way heap does is to prevent out-of-control programs from having as much adverse impact on the entire machine when used in a more local scope (such as a while or for loop) or in several scopes, the memory accumulates per iteration/scope and is not released until the function exits: this contrasts with normal variables defined in the scope of a control structure (e.g. for {int i = 0; i < 2; ++i) { X } would accumulate alloca-ed memory requested at X, but memory for a fixed-sized array would be recycled per iteration). modern compilers typically do not inline functions that call alloca, but if you force them then the alloca will happen in the callers' context (i.e. the stack won't be released until the caller returns) a long time ago alloca transitioned from a non-portable feature/hack to a Standardised extension, but some negative perception may persist the lifetime is bound to the function scope, which may or may not suit the programmer better than malloc's explicit control having to use malloc encourages thinking about the deallocation - if that's managed through a wrapper function (e.g. WonderfulObject_DestructorFree(ptr)), then the function provides a point for implementation clean up operations (like closing file descriptors, freeing internal pointers or doing some logging) without explicit changes to client code: sometimes it's a nice model to adopt consistently in this pseudo-OO style of programming, it's natural to want something like WonderfulObject* p = WonderfulObject_AllocConstructor(); - that's possible when the "constructor" is a function returning malloc-ed memory (as the memory remains allocated after the function returns the value to be stored in p), but not if the "constructor" uses alloca a macro version of WonderfulObject_AllocConstructor could achieve this, but "macros are evil" in that they can conflict with each other and non-macro code and create unintended substitutions and consequent difficult-to-diagnose problems missing free operations can be detected by ValGrind, Purify etc. but missing "destructor" calls can't always be detected at all - one very tenuous benefit in terms of enforcement of intended usage; some alloca() implementations (such as GCC's) use an inlined macro for alloca(), so runtime substitution of a memory-usage diagnostic library isn't possible the way it is for malloc/realloc/free (e.g. electric fence) some implementations have subtle issues: for example, from the Linux manpage:

在许多系统中,alloca()不能在函数调用的参数列表中使用,因为由alloca()保留的堆栈空间将出现在堆栈中用于函数参数的空间中间。

我知道这个问题被标记为C,但作为一名c++程序员,我认为我应该使用c++来说明alloca的潜在效用:下面的代码(以及这里的ideone)创建了一个向量,跟踪不同大小的多态类型,这些类型是堆栈分配的(生命期与函数返回绑定),而不是堆分配的。

#include <alloca.h>
#include <iostream>
#include <vector>

struct Base
{
    virtual ~Base() { }
    virtual int to_int() const = 0;
};

struct Integer : Base
{
    Integer(int n) : n_(n) { }
    int to_int() const { return n_; }
    int n_;
};

struct Double : Base
{
    Double(double n) : n_(n) { }
    int to_int() const { return -n_; }
    double n_;
};

inline Base* factory(double d) __attribute__((always_inline));

inline Base* factory(double d)
{
    if ((double)(int)d != d)
        return new (alloca(sizeof(Double))) Double(d);
    else
        return new (alloca(sizeof(Integer))) Integer(d);
}

int main()
{
    std::vector<Base*> numbers;
    numbers.push_back(factory(29.3));
    numbers.push_back(factory(29));
    numbers.push_back(factory(7.1));
    numbers.push_back(factory(2));
    numbers.push_back(factory(231.0));
    for (std::vector<Base*>::const_iterator i = numbers.begin();
         i != numbers.end(); ++i)
    {
        std::cout << *i << ' ' << (*i)->to_int() << '\n';
        (*i)->~Base();   // optionally / else Undefined Behaviour iff the
                         // program depends on side effects of destructor
    }
}

每个人都已经指出了堆栈溢出潜在的未定义行为,但我应该提到的是,Windows环境有一个很好的机制来捕捉这种情况,使用结构化异常(SEH)和保护页面。由于堆栈只在需要时增长,因此这些保护页驻留在未分配的区域。如果你对它们进行分配(通过溢出堆栈),就会抛出一个异常。

您可以捕获这个SEH异常并调用_resetstkoflw来重置堆栈并继续您的快乐之路。这并不理想,但这是另一种机制,至少可以在事情发生时知道哪里出了问题。*nix可能有类似的东西,但我不知道。

我建议通过包装alloca并在内部跟踪它来限制您的最大分配大小。如果你真的很认真,你可以在函数的顶部设置一些作用域哨兵来跟踪函数作用域中的任何分配,并检查它与项目允许的最大数量是否一致。

此外,除了不允许内存泄漏之外,alloca也不会导致内存碎片,这是非常重要的。我不认为alloca是不好的做法,如果你明智地使用它,这基本上适用于所有事情。: -)