5

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


细节:

众所周知,alloca()是一个有争议的功能。乱用,会导致栈溢出。明智地使用,它可以通过避免堆分配从紧密循环中减少几纳秒。在这个关于为什么alloca被认为不好的问题中,几个最佳答案提倡偶尔使用alloca.

从堆栈分配的另一种方法是简单地声明一个固定大小的数组。这种策略的一个例子可以在Howard Hinnant 的 stack allocatorarena的类中找到。(该代码当然是 C++,但这个概念仍然适用于 C。)

使用alloca与固定大小数组的权衡是什么?什么时候,如果有的话,一个明显优于另一个?是否只是一个性能问题,应该在每种情况下进行经验测试(当性能是关键目标并且已经确定热点时)?固定大小的数组更加悲观——它总是分配我们愿意在堆栈上分配的数量——但尚不清楚这是好是坏。

为了尽可能清楚,这是两个函数实现的一个非常简单的示例,似乎有理由使用其中一个alloca或一个固定大小的数组:

#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);
}

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

4

1 回答 1

4

alloca()使用与固定大小数组的权衡是什么?

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

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

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

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

  5. VLA 的优点/缺点就像alloca()是 C99 标准的一部分,但在 C11 中只是可选的。

于 2016-10-03T22:14:12.813 回答