web-dev-qa-db-ja.com

スタックサイズのulimit-プロセスごとまたはスレッドごとの制限?

したがって、Solarisにはスタックスペースが不足しているプログラムがあります。

これを調査している間に、スタックのulimitが何であるかを簡単に調べました。

user@solaris-box:~$ ulimit -a
...
stack size              (kbytes, -s) 8192

したがって、スタックサイズの制限は8メガバイトです。しかし、これはプロセス全体の制限ですか?

プロセスに10のスレッドがある場合、スレッドごとに819kしか許可されませんか? (または8MiBまでのいくつかの組み合わせ?)

これに関するドコは見つかりません。

2
Kingsley

[〜#〜]要約[〜#〜]

メインスレッドでは、setrlimit()を呼び出す必要があります(おそらくulimitを使用して)beforeプロセスを開始して、より大きなスタックサイズが有効です。

プロセスによって開始されたスレッドの場合、スレッドのスタックサイズはpthread_attr_setstacksize()/setrlimit()stack sizeリソース制限の影響をまったく受けないため、 getrlimit() を使用する必要があります。

コードは次のようにする必要があります。

pthread_attr attr;
pthread_attr_init( &attr );

// 32MB stack size example - should **NOT** hardcode this
// but get it from an environment variable or property setting
size_t stacksize = 32UL * 1024UL * 1024UL;
pthread_attr_setstacksize( &attr, stacksize );

pthread_create( &tid, &attr, start_func, thread_arg );

現在のスタックサイズ制限からスレッドスタックサイズを取得できます。

struct rlimit limits;

getrlimit( RLIMIT_STACK, &limits );
size_t stacksize = limits.rlim_cur; // use rlim_max for hard limit

(独自のスレッドを作成するライブラリを使用している場合、そのライブラリには、OpenMPIなどのスレッドスタックサイズを設定する独自のドキュメント化されたメソッドがある場合があります。)

詳細な回答

リソース制限は、コマンドラインから the ulimitユーティリティ によって設定されます。

truss -f -a -vall -o /tmp/truss.out /usr/bin/ulimit -aを実行すると、

address space limit (kbytes)   (-M)  unlimited
core file size (blocks)        (-c)  unlimited
cpu time (seconds)             (-t)  unlimited
data size (kbytes)             (-d)  unlimited
file size (blocks)             (-f)  unlimited
locks                          (-x)  not supported
locked address space (kbytes)  (-l)  not supported
message queue size (kbytes)    (-q)  not supported
Nice                           (-e)  not supported
nofile                         (-n)  1024
nproc                          (-u)  29995
pipe buffer size (bytes)       (-p)  5120
max memory size (kbytes)       (-m)  not supported
rtprio                         (-r)  not supported
socket buffer size (bytes)     (-b)  5120
sigpend                        (-i)  128
stack size (kbytes)            (-s)  8192
swap size (kbytes)             (-w)  not supported
threads                        (-T)  not supported
process size (kbytes)          (-v)  unlimited

そして、/tmp/truss.outを調べると、

7752:   execve("/usr/bin/ulimit", 0xFFFF80FFBFFFF9E8, 0xFFFF80FFBFFFFA00)  argc = 2
7752:    argv: /usr/bin/ulimit -a
7752:   sysinfo(SI_MACHINE, "i86pc", 257)       = 6

  much deleted extraneous data (loading shared libraries, etc)...

7752:   getrlimit(RLIMIT_VMEM, 0xFFFF80FFBFFFD4B0)  = 0
7752:       cur = RLIM64_INFINITY  max = RLIM64_INFINITY
7752:   getrlimit(RLIMIT_CORE, 0xFFFF80FFBFFFD4B0)  = 0
7752:       cur = RLIM64_INFINITY  max = RLIM64_INFINITY
7752:   getrlimit(RLIMIT_CPU, 0xFFFF80FFBFFFD4B0)   = 0
7752:       cur = RLIM64_INFINITY  max = RLIM64_INFINITY
7752:   getrlimit(RLIMIT_DATA, 0xFFFF80FFBFFFD4B0)  = 0
7752:       cur = RLIM64_INFINITY  max = RLIM64_INFINITY
7752:   getrlimit(RLIMIT_FSIZE, 0xFFFF80FFBFFFD4B0) = 0
7752:       cur = RLIM64_INFINITY  max = RLIM64_INFINITY
7752:   getrlimit(RLIMIT_NOFILE, 0xFFFF80FFBFFFD4B0)    = 0
7752:       cur = 1024  max = 65536
7752:   sysconfig(_CONFIG_CHILD_MAX)            = 29995
7752:   pathconf("/", _PC_PIPE_BUF)         = 5120
7752:   pathconf("/", _PC_PIPE_BUF)         = 5120
7752:   sysconfig(_CONFIG_SIGQUEUE_MAX)         = 128
7752:   getrlimit(RLIMIT_STACK, 0xFFFF80FFBFFFD4B0) = 0
7752:       cur = 8388608  max = RLIM64_INFINITY
7752:   getrlimit(RLIMIT_VMEM, 0xFFFF80FFBFFFD4B0)  = 0
7752:       cur = RLIM64_INFINITY  max = RLIM64_INFINITY
7752:   write(1, " a d d r e s s   s p a c".., 942) = 942

ulimitgetrlimit()(およびsetrlimit())ライブラリ関数 を使用してリソース制限を取得/設定していることがわかります。

あたり getrlimit()/setrlimit()manページ (太字部分に注意):

RLIMIT_STACK

プロセスのスタックの最大サイズ(バイト単位)。システムは、この制限を超えてスタックを自動的に拡張しません。

プロセス内で、setrlimit()はスタックのサイズの制限を増やしますが、その増加に対応するために現在のメモリセグメントを移動しません。プロセススタックが限界まで成長できることを保証するには、新しいスタックサイズを使用するプロセスを実行する前に、限界を変更する必要があります

マルチスレッドプロセス内では、setrlimit()は、呼び出しスレッドがメインスレッドでない場合、呼び出しスレッドのスタックサイズ制限に影響を与えませんRLIMIT_STACKに対するsetrlimit()の呼び出しは、メインスレッドのスタックにのみ影響を与えるので、メインスレッドからのみ行う必要があります。

SIGSEGVシグナルがプロセスに送信されます。プロセスがSIGSEGVを保持または無視している場合、またはSIGSEGVをキャッチしていて、代替スタックを使用する準備をしていない場合(sigaltstack(2)を参照)、SIGSEGVの後処理は、それが実行される前にSIG_DFLに設定されます。送信されました。

したがって、メインスレッドではない、プロセスによって作成されたスレッドのスタックサイズは、プロセスのRLIMIT_STACKリソース制限の影響を受けません。そして、setrlimit()[〜#〜] before [〜#〜]を呼び出して、プロセスが(親プロセスで)開始し、スタックサイズの制限を大きくすると、実際に効果的です。

pthread_create() manページ ごと:

pthread_create()で作成された新しいスレッドは、stackaddr属性で指定されたスタックを使用し、スタックはstacksize属性で指定されたバイト数だけ継続します。デフォルトでは、スタックサイズは、32ビットプロセスの場合は1メガバイト、64ビットプロセスの場合は2メガバイトです( pthread_attr_setstacksize(3C) を参照)。 stackaddr属性とstacksize属性の両方にデフォルトが使用されている場合、pthread_create()は、32ビットプロセス用に少なくとも1メガバイト、64ビットプロセス用に2メガバイトの新しいスレッド用のスタックを作成します。 (スタックサイズのカスタマイズについては、「注」を参照してください)。

...

注意事項

...

ユーザー指定のスタックサイズは、値PTHREAD_STACK_MINより大きい必要があります。最小スタックサイズは、ユーザースレッド関数start_funcのスタックフレームに対応しない場合があります。スタックサイズを指定する場合は、最小要件に加えて、start_func要件と、順番に呼び出す関数に対応する必要があります。

通常、スレッドのランタイムスタック要件を決定することは非常に困難です。 PTHREAD_STACK_MINは、NULLstart_funcを実行するために必要なスタックストレージの量を指定します。スタックストレージの合計ランタイム要件は、ランタイムリンクを行うために必要なストレージ、スレッドが呼び出すライブラリランタイム(printf()として)に必要なストレージの量によって異なります。これらのストレージパラメータはプログラムの実行前にはわからないため、デフォルトのスタックを使用することをお勧めします。ランタイム要件がわかっている場合、またはデフォルトよりも大きいスタックを使用する場合は、独自のスタックを指定するのが理にかなっています。

2
Andrew Henle