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。据我所知,从alloca
VLA 和 VLA 获得的内存具有基本相同的行为,因此该问题也适用于 VLA。如果这种理解是错误的,只需提及它。