制限を受ける(2)マニュアルページには次の定義があります。
RLIMIT_AS プロセスの仮想メモリ(アドレス空間)の最大サイズ(バイト単位)。この制限はbrk(2)、mmap(2)、およびmremap(2)への呼び出しに影響し、この制限を超えるとENOMEMエラーで失敗します。返品自動スタック拡張失敗します(sigatstack(2)で利用可能な代替スタックがない場合、プロセスを終了するためにSIGSEGVが作成されます)。値が long なので、32 ビット long を使用するマシンでは、この制限が最大 2GiB か、このリソースが無制限です。
ここで「自動スタック拡張」とはどういう意味ですか? Linux / UNIX環境のスタックは必要に応じて増加しますか?それでは、具体的なメカニズムは何ですか?
答え1
Linuxの正確なメカニズムは次のとおりです。匿名マッピングのページエラー処理あなた「増加する割り当て」であることを確認してください。スタックのように拡張する必要があります。 VMゾーン履歴にそれを行う必要があるとマークされている場合は、開始アドレスを調整してスタックを拡張できます。
ページ障害が発生した場合は、アドレスに基づいてスタック拡張を介して処理できます(エラーの削除も可能です)。すべてのユーザープログラムは、仮想メモリの「失敗時の成長」動作を要求し、システムコールMAP_GROWSDOWN
にフラグを渡すことができます。mmap
ユーザープログラムでもこのメカニズムを使用できます。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
long page_size = sysconf(_SC_PAGE_SIZE);
void *mem = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_GROWSDOWN|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (MAP_FAILED == mem) {
perror("failed to create growsdown mapping");
return EXIT_FAILURE;
}
volatile char *tos = (char *) mem + page_size;
int i;
for (i = 1; i < 10 * page_size; ++i)
tos[-i] = 42;
fprintf(stderr, "inspect mappping for originally page-sized %p in /proc... press any key to continue...\n", mem);
(void) getchar();
if (munmap(mem, page_size))
perror("failed munmap");
return EXIT_SUCCESS;
}
プロンプトが表示されたら、プログラムのpid(pass ps
)を見つけて、元の/proc/$THAT_PID/maps
領域がどのように大きくなるかを確認します。
答え2
はい、スタックは動的に増加します。スタックはメモリの上部にあり、ヒープに向かって下向きに増加します。
--------------
| Stack |
--------------
| Free memory|
--------------
| Heap |
--------------
.
.
新しい関数が呼び出されると、ヒープは上に向かって大きくなり(mallocが実行されるたびに)、スタックは下に伸びます。ヒープはプログラムのBSS部分の上に配置されます。これは、プログラムのサイズとヒープにメモリを割り当てる方法も、プロセスの最大スタックサイズに影響を与えることを意味します。通常、スタックサイズは無限です(ヒープとスタック領域が出会うか上書きされるまでスタックオーバーフローとSIGSEGVが発生します。)
これはユーザープロセスでのみ機能し、カーネルスタックは常に固定されています(通常8 KB)。