2016-10-03 5 views
4

Когда 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. Если это понимание неверно, просто упоминайте об этом.

+0

Это код 'C'. 1) Вызов 'malloc' не вызывается - это не работает с C++ и 2) На языке C++ нет VLA. – PaulMcKenzie

+0

'foo_fixed' комбинезоны на одну вещь. –

+0

@MadPhysicist Я должен был быть более креативным. Это не отличный пример. Представьте, что 'mem_needed' фактически описывает нужную память, и мы делаем больше, чем пишем« abc ». – Praxeolitic

ответ

3

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

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

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

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

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

  5. VLA pros/cons похоже на alloca(), за исключением того, что это часть стандарта C99, но только необязательная в C11.

+0

Не могли бы вы привести пример инструмента, который анализирует стек глубина? Я не знаком с таким анализом. Благодарю. – Praxeolitic

+0

@Praxeolitic 1st, который приходит на ум: [CCS] (http://www.ccsinfo.com/content.php?page=compilers) анализирует использование стека/памяти. Не допуская рекурсии, абсолютная максимальная глубина/использование памяти стека вычисляется и очень важна для компиляторов, работающих в ограниченных средах с встроенной памятью. – chux

Смежные вопросы