web-dev-qa-db-ja.com

配列はいつc#のスタックに割り当てられますか?

私は物事がいつスタックに割り当てられるかを理解しようとしてきましたが、配列(またはその中の値)をスタックに割り当てる方法を理解できません。

この例では:

public void foo()
{
    int bar[] = new int [10];
}

10個のint構造体がヒープに割り当てられ、それらへのポインターのみがスタックに割り当てられますよね?

固定サイズの配列をスタックに配置するにはどうすればよいですか?定義したスタクトを使用している場合はどうなりますか?

配列サイズをパラメーターとして関数に渡す場合はどうなりますか?

私が理解している限り、関数が呼び出されたときにサイズがわかっていれば、関数が呼び出されたときにスタック上で任意のサイズの配列を取得することに問題はないはずです。

私もこれに悩まされるべきですか?私が理解している限り、この固定サイズの配列をスタックに配置すると、ヒープの割り当てが行われないため、パフォーマンスが向上します。

19
morowinder

10個のint構造体がヒープに割り当てられ、それらへのポインターのみがスタックに割り当てられますよね?

はい正解。

固定サイズの配列をスタックに配置するにはどうすればよいですか?定義したスタクトを使用している場合はどうなりますか?

stackallocキーワード はこの目的に役立ちます。ただし、これは安全でないコンテキストでのみ機能します。これは、ほとんどのシナリオで不必要に制限される要因であり、パフォーマンスのトレードオフの価値はありません。

例:

public void unsafe foo()
{
    int* bar = stackalloc int [10];
}

配列のメンバーにアクセスするには、 ポインタ演算 を使用する必要があります。

配列サイズをパラメーターとして関数に渡す場合はどうなりますか?私が理解している限り、関数が呼び出されたときにサイズがわかっていれば、関数が呼び出されたときにスタック上で任意のサイズの配列を取得することに問題はないはずです。

期待どおりに機能します:

public void unsafe foo(int length)
{
    int* bar = stackalloc int [length];
}

私もこれに悩まされるべきですか?私が理解している限り、この固定サイズの配列をスタックに配置すると、ヒープの割り当てが行われないため、パフォーマンスが向上します。

いいえ、一般的にはありません。重い数学計算、暗号化、圧縮など、パフォーマンスが非常に重要な特定のシナリオを処理しない限り、実際のメリットはありません。

また、パフォーマンス関連の説明については、 この質問 を参照してください。

17
Ondrej Tucny