Когда alloca()
предпочтительнее памяти, выделенной в стеке, объявляя массив фиксированного размера?Фиксированный размер массива vs alloca (или VLA)
Детали:
Как мы знаем, alloca()
является спорной функцией. Используется безрассудно, это может вызвать переполнение стека. Используемый разумно, он может сбрить несколько наносекунд из жесткой петли, избегая распределения кучи. В this question о том, почему alloca
считается плохим, некоторые из главных ответов защищают использование alloca
.
Другой способ выделения из стека - просто объявить массив фиксированного размера. Пример этой стратегии можно найти в классе arena
в Howard Hinnant's stack allocator. (Этот код, конечно, 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
Св.Влас , Насколько мне известно, память, полученная от alloca
и VLA, имеет, по сути, одно и то же поведение, поэтому вопрос относится и к VLA. Если это понимание неверно, просто упоминайте об этом.
Это код 'C'. 1) Вызов 'malloc' не вызывается - это не работает с C++ и 2) На языке C++ нет VLA. – PaulMcKenzie
'foo_fixed' комбинезоны на одну вещь. –
@MadPhysicist Я должен был быть более креативным. Это не отличный пример. Представьте, что 'mem_needed' фактически описывает нужную память, и мы делаем больше, чем пишем« abc ». – Praxeolitic