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

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

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

この問題を調査しながら、スタックのulimitが何であるかを簡単に調べました。

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

したがって、スタックサイズは8MBに制限されます。しかし、これはプロセスの制限ですか?

私のプロセスに10個のスレッドがあり、各スレッドに819kしか許可されていない場合はどうなりますか? (またはこれらの組み合わせで最大8MiBまで可能ですか?)

これに関するドキュメントが見つかりません。

ベストアンサー1

一般化する

メインスレッドの場合は呼び出す必要がありますsetrlimit()(おそらくを使用してulimit)。今後このプロセスは、より大きなスタックサイズが有効であることを確認するために開始されます。

プロセスが開始されたスレッドの場合は使用する必要があります。pthread_attr_setstacksize()スレッドスタックサイズは、stack size/のリソース制限にまったく影響されないためです。setrlimit()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などのスレッドスタックサイズを設定する文書化された独自の方法があります。)

詳細な回答

リソース制限はコマンドラインで設定されます。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

ulimit私たちは使用するのを見るgetrlimit()(および)ライブラリsetrlimit()機能リソース制限を取得または設定します。

すべてこのページgetrlimit()setrlimit() man(太い部分を参照):

RLIMIT_STACK

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

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

マルチスレッドプロセスではsetrlimit()呼び出しスレッドが基本スレッドでない場合、呼び出しスレッドのスタックサイズの制限には影響しません。setrlimit()forへの呼び出しはRLIMIT_STACKメインスレッドのスタックにのみ影響し、メインスレッドでのみ行われる必要があります(存在する場合)。

信号がSIGSEGVプロセスに送信されます。プロセスがSIGSEGVを維持または無視するか、キャプチャしているがSIGSEGVまだ代替スタックの使用をスケジュールしていない場合(参考資料を参照sigaltstack(2))、処理は送信前にSIGSEGV設定されます。SIG_DFL

したがって、メインスレッド以外のプロセスによって生成されたスレッドのスタックサイズは、RLIMIT_STACKプロセスリソース制限の影響を受けません。電話する必要がありますsetrlimit() 今後より大きなスタックサイズ制限が実際に適用されることを確認するために、プロセスは親プロセスで開始されます。

すべてマニュアルpthread_create()ページ:

作成された新しいスレッドは属性pthread_create()で指定されたスタックを使用し、stackaddrスタックは属性で指定されたバイト数の間持続しますstacksize。デフォルトでは、スタックサイズは32ビットプロセスの場合は1MB、64ビットプロセスの場合は2MBです(バラよりpthread_attr_setstacksize(3C))。プロパティの両方にデフォルト値が使用されている場合は、 32ビットプロセスの場合stackaddrは少なくとも1 MB、64ビットプロセスの場合は2 MBの新しいスレッドのスタックが作成されます。 (カスタムスタックサイズの説明を参照してください)。stacksizepthread_create()

...

ノート

...

ユーザーが指定したスタックサイズは値より大きくなければなりません PTHREAD_STACK_MIN。最小スタックサイズは、ユーザースレッド関数のスタックフレームに対応できない場合がありますstart_func。スタックサイズが指定されている場合は、start_func最小要件に加えて呼び出すことができる要件と機能も満たす必要があります。

スレッドのランタイムスタック要件を決定することはしばしば困難です。PTHREAD_STACK_MIN.txtファイルを実行するために必要なスタックストレージ容量を指定しますNULL start_func。スタックストアのフルランタイム要件は、ランタイム接続を実行するために必要なリポジトリと、スレッドが呼び出すprintf()ライブラリランタイムに必要なリポジトリの量によって異なります。このように保存されたパラメータはプログラムが実行されるまでは不明であるため、デフォルトのスタックを使用するのが最善です。ランタイム要件を知っている場合、またはデフォルトよりも大きいスタックを使用することを決定した場合は、直接指定することをお勧めします。

おすすめ記事