関数を呼び出すと、新しい「名前空間」がスタックに割り当てられます。これが、関数がローカル変数を持つ方法です。関数が関数を呼び出し、関数が関数を呼び出すと、名前空間のこの深い階層を維持するために、スタック上により多くのスペースを割り当て続けます。
大量のスタックスペースを使用するプログラムを抑制するために、通常は ulimit -s
を介して制限が設定されます . ulimit -s unlimited
を介してその制限を削除すると 、私たちのプログラムは、最終的にシステムが完全にメモリを使い果たすまで、増え続けるスタックのために RAM を使い続けることができます。
int eat_stack_space(void) { return eat_stack_space(); }
// If we compile this with no optimization and run it, our computer could crash.
通常、大量のスタック スペースを使用するのは偶発的であるか、スタックにあまり依存すべきではない非常に深い再帰の兆候です。したがって、スタック制限。
パフォーマンスへの影響は軽微ですが、存在します。 time
の使用 コマンドを実行すると、スタック制限をなくすとパフォーマンスが数分の一秒向上することがわかりました (少なくとも 64 ビット Ubuntu では)。
ulimit -s unlimited
スタックを無制限に成長させます。
これにより、再帰によってプログラムを作成する場合、特にプログラムが末尾再帰的ではなく (コンパイラがそれらを「最適化」できる)、再帰の深さが大きい場合に、プログラムのクラッシュを防ぐことができます。
スタック サイズ 缶 確かに無制限です。 _STK_LIM
デフォルトです 、 _STK_LIM_MAX
include/asm-generic/resource.h
からわかるように、アーキテクチャごとに異なるものです :
/*
* RLIMIT_STACK default maximum - some architectures override it:
*/
#ifndef _STK_LIM_MAX
# define _STK_LIM_MAX RLIM_INFINITY
#endif
この例からわかるように、ジェネリック値は無限です。ここで RLIM_INFINITY
繰り返しますが、一般的なケースでは次のように定義されています:
/*
* SuS says limits have to be unsigned.
* Which makes a ton more sense anyway.
*
* Some architectures override this (for compatibility reasons):
*/
#ifndef RLIM_INFINITY
# define RLIM_INFINITY (~0UL)
#endif
したがって、本当の答えは次のとおりだと思います-スタックサイズはいくつかのアーキテクチャによって制限される可能性があり、無制限のスタックトレースは_STK_LIM_MAX
を意味します に定義されており、無限大の場合は無限大です。無限に設定することの意味とそれが持つ可能性のある影響の詳細については、他の回答を参照してください。それは私のものよりもはるかに優れています.