5

alloca()固定サイズの配列を宣言してスタックに割り当てられたメモリよりも適しているのはいつですか?


詳細:

私たちが知っているようにalloca()、物議を醸す関数です。むやみに使用すると、スタック オーバーフローが発生する可能性があります。慎重に使用すると、ヒープの割り当てを回避することで、タイトなループから数ナノ秒短縮できます。なぜが悪いと見なされるのかについてのこの質問では、上位の回答のいくつかが を時折使用することを推奨します。allocaalloca

スタックから割り当てるもう 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 にも当てはまります。その理解が間違っている場合は、それについて言及してください。

4

1 に答える 1

4

alloca()固定サイズの配列とのトレードオフは何ですか?

  1. 携帯性。alloca()標準 C ライブラリ関数ではありません。固定サイズの配列は言語の一部です。

  2. 分析可能性。コードのメモリ使用量を定期的に分析するツールは、固定サイド アレイによるスタック深度分析をサポートしています。 alloc()分析可能性は存在する場合と存在しない場合があります。

  3. スペース効率。 alloca()禁止されたメモリ空間を割り当てます。固定サイズの配列は過剰に割り当てられる傾向があります。

  4. コードの効率/速度は確かに実装上の問題であり、パフォーマンスを比較するにはプロファイリングが必要です。大きな違いは期待できません。

  5. VLA の長所/短所はalloca()、C99 標準の一部でありながら、C11 ではオプションのみであることを除いて似ています。

于 2016-10-03T22:14:12.813 に答える