alloca()
固定サイズの配列を宣言してスタックに割り当てられたメモリよりも適しているのはいつですか?
詳細:
私たちが知っているようにalloca()
、物議を醸す関数です。むやみに使用すると、スタック オーバーフローが発生する可能性があります。慎重に使用すると、ヒープの割り当てを回避することで、タイトなループから数ナノ秒短縮できます。なぜが悪いと見なされるのかについてのこの質問では、上位の回答のいくつかが を時折使用することを推奨しています。alloca
alloca
スタックから割り当てるもう 1 つの方法は、単純に固定サイズの配列を宣言することです。この戦略の例は、 Howard Hinnant の stack allocator のarena
クラスにあります。(そのコードはもちろん C++ ですが、概念は C にも当てはまります。)
alloca
固定サイズの配列とのトレードオフは何ですか? 一方が他方よりも明らかに好ましいのはいつですか?個々の状況 (パフォーマンスが主要な目標であり、ホットスポットが既に特定されている場合) で経験的にテストする必要があるのは、単にパフォーマンスの問題ですか? 固定サイズの配列はより悲観的です。スタックに割り当てたい分だけ常に割り当てますが、これが良いか悪いかは明らかではありません。
できるだけ明確にするためにalloca
、固定サイズの配列を使用する理由と思われる 2 つの関数実装の非常に単純な例を次に示します。
#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 にも当てはまります。その理解が間違っている場合は、それについて言及してください。