通过声明一个固定大小的数组,什么时候alloca()
优于堆栈上分配的内存?
详细说明:
众所周知,alloca()
是一项有争议的功能。鲁莽地使用它会导致堆栈溢出。明智地使用它可以通过避免堆分配从紧密循环中减少几纳秒。在this question中,为什么alloca
被认为是错误的,有几个主要答案主张偶尔使用alloca
。
从堆栈分配的另一种方法是简单地声明一个固定大小的数组。可以在Howard Hinnant's stack allocator中的arena
课程中找到此策略的示例。 (该代码当然是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。据我所知,从alloca
和VLA获得的内存具有基本相同的行为,因此该问题也适用于VLA。如果这种理解是错误的,那就提一下吧。
答案 0 :(得分:3)
使用
onClick
与固定大小数组相比,有哪些权衡取舍?
可移植性。 alloca()
不是标准的C库函数。固定大小的数组是该语言的一部分。
可分析。分析代码存储器使用的工具定期支持通过固定侧阵列进行堆栈深度分析。 alloca()
可分析性可能存在/可能不存在。
空间效率。 alloc()
分配被禁止的内存空间。固定大小的数组倾向于过度分配。
代码效率/速度肯定是一个实现问题,需要进行分析才能比较性能。预计不会有显着差异。
VLA优点/缺点与alloca()
类似,不同之处在于它是C99标准的一部分,但在C11中只是可选的。