Фиксированный размер массива против alloca (или VLA)

Когда alloca() предпочтительнее, чем память, выделенная в стеке путем объявления массива фиксированного размера?


Подробности:

Как мы знаем, alloca() является спорной функцией. Неосторожное использование может привести к переполнению стека. При разумном использовании, он может сократить несколько наносекунд из узкой петли, избегая выделения кучи. В этот вопрос о том, почему alloca считается плохим, некоторые из лучших ответов выступают за случайный использование alloca,

Другой способ выделения из стека — просто объявить массив фиксированного размера. Пример этой стратегии можно найти в arena класс в Распределитель стека Говарда Хиннанта. (Этот код, конечно, C ++, но концепция все еще применима к C.)

Каковы компромиссы использования alloca vs массив с фиксированным размером? Когда, если вообще, одно явно предпочтительнее другого? Является ли это просто вопросом производительности, который должен быть проверен эмпирически в каждой отдельной ситуации (когда производительность является ключевой целью, и горячая точка уже определена)? Массив фиксированного размера более пессимистичен — он всегда выделяет столько, сколько мы хотим выделить в стеке, — но не ясно, хорошо это или плохо.

Просто чтобы быть как можно более ясным, вот очень простой пример двух реализаций функций, где кажется целесообразным использовать либо 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. Если это понимание неверно, просто упомяните об этом.

4

Решение

Каковы компромиссы использования alloca() vs массив с фиксированным размером?

  1. Переносимость. alloca() не является стандартной библиотечной функцией C. Массивы фиксированного размера являются частью языка.

  2. Analyzability. Инструменты, которые анализируют использование памяти кода, регулярно поддерживают анализ глубины стека с помощью фиксированных боковых массивов. alloc() анализируемость может / не может существовать.

  3. Пространственная эффективность. alloca() выделяет запрещенную область памяти. Массивы фиксированного размера имеют тенденцию перераспределять.

  4. Эффективность / скорость кода, безусловно, является проблемой реализации, и для сравнения производительности потребуется профилирование. Существенной разницы не ожидается.

  5. VLA плюсы / минусы это как alloca() за исключением того, что это является частью стандарта C99, но только факультативно в C11.

3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector