固定大小的数组与 alloca(或 VLA)

Pra*_*tic 5 c c++ performance alloca

什么时候alloca()通过声明固定大小的数组来分配在堆栈上的内存更可取?


细节:

As we know, alloca() is a controversial function. Used recklessly, it can cause stack overflow. Used judiciously, it can shave a few nanoseconds from a tight loop by avoiding heap allocation. In this question about why alloca is considered bad, several of the top answers advocate for the occasional use of alloca.

Another way to allocate from the stack is to simply declare a fixed size array. An example of this strategy can be found in the arena class in Howard Hinnant's stack allocator. (That code is of course C++ but the concept is still applicable to C.)

What are the tradeoffs of using alloca vs a fixed size array? When, if ever, is one clearly preferable to the other? Is it simply a question of performance that should be empirically tested in each individual situation (when performance is a key goal and a hotspot has already been identified)? The fixed size array is more pessimistic -- it always allocates as much as we're willing to allocate on the stack -- but it's not clear whether this is good or bad.

Just to be as clear as possible, here's a very simple example of two function implementations where it seems reason to use either alloca or a fixed size array:

#include <alloca.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

void foo_alloca(const size_t mem_needed) {
    printf("foo_alloca(%zu)\n", mem_needed);
    char* mem;
    bool used_malloc = false;
    if (mem_needed <= 100)
        mem = alloca(mem_needed);
    else {
        mem = malloc(mem_needed);
        used_malloc = true;
    }
    assert(mem_needed != 0);
    // imagine we do something interesting with mem here
    mem[0] = 'a';
    mem[1] = 'b';
    mem[2] = 'c';
    mem[3] = '\0';
    puts(mem);
    if (used_malloc)
        free(mem);
}

void foo_fixed(const size_t mem_needed) {
    printf("foo_fixed(%zu)\n", mem_needed);
    char* mem;
    char stack_mem[100];
    bool used_malloc = false;
    if (mem_needed <= 100)
        mem = stack_mem;
    else {
        mem = malloc(mem_needed);
        used_malloc = true;
    }
    assert(mem_needed != 0);
    // imagine we do something interesting with mem here
    mem[0] = 'a';
    mem[1] = 'b';
    mem[2] = 'c';
    mem[3] = '\0';
    puts(mem);
    if (used_malloc)
        free(mem);
}

int main()
{
    foo_alloca(30);
    foo_fixed(30);
    foo_alloca(120);
    foo_fixed(120);
}
Run Code Online (Sandbox Code Playgroud)

另一个非常相似的选项alloca是 VLA。据我所知,从allocaVLA 和 VLA获得的内存具有基本相同的行为,因此该问题也适用于 VLA。如果这种理解是错误的,请提及它。

chu*_*ica 4

alloca()使用固定大小数组与使用固定大小数组有何权衡?

  1. 可移植性。alloca()不是标准 C 库函数。固定大小的数组是该语言的一部分。

  2. 可分析性。分析代码内存使用情况的工具定期支持通过固定侧数组进行堆栈深度分析。 alloc()可分析性可能存在也可能不存在。

  3. 空间效率。 alloca()分配指定的内存空间。固定大小的数组往往会过度分配。

  4. 代码效率/速度当然是一个实施问题,需要进行分析来比较性能。预计不会出现显着差异。

  5. VLA 的优点/缺点alloca()与 C99 标准的一部分类似,但在 C11 中仅可选。