スタックメモリの制限が割り当てられていないようです(とにかく、無制限のスタックではできませんでした)。 https://www.kernel.org/doc/Documentation/vm/overcommit-accounting によると:
<ブロック引用>C 言語スタックの成長は、暗黙的な mremap を行います。絶対的な保証が必要で、エッジの近くで実行する場合は、必要になると思われる最大サイズのスタックを mmap する必要があります。典型的なスタックの使用法では、これは大した問題ではありませんが、本当に気にする場合はまれなケースです
ただし、スタックの mmap はコンパイラの目標になります (そのためのオプションがある場合)。
編集:x84_64 Debian マシンでいくつかのテストを行った後、システム コールなしでスタックが大きくなることがわかりました (strace
によると)。 )。したがって、これはカーネルが自動的にそれを拡張することを意味します (これが上記の「暗黙的」の意味です)、つまり、明示的な mmap
なしで /mremap
これを確認する詳細な情報を見つけるのは非常に困難でした。 Mel Gorman による Understanding The Linux Virtual Memory Manager をお勧めします。答えはセクション 4.6.1 ページ フォールトの処理 にあると思います。 、「リージョンは無効ですが、スタックのような拡張可能なリージョンの横にあります」という例外と、対応するアクション「リージョンを拡張してページを割り当てる」があります。 D.5.2スタックの拡張も参照してください .
Linux メモリ管理に関するその他の参考文献 (ただし、スタックについてはほとんど何もありません):
- メモリに関するよくある質問
- Ulrich Drepper によるメモリについてすべてのプログラマが知っておくべきこと
編集 2:この実装には欠点があります。まれに、スタックが制限よりも大きくなる場合でも、スタック ヒープの衝突が検出されないことがあります。その理由は、スタック内の変数への書き込みが、割り当てられたヒープ メモリで終了する可能性があるためです。この場合、ページ フォールトは発生せず、カーネルはスタックを拡張する必要があることを認識できません。 gcc-help リストで開始した GNU/Linux での Silent stack-heap collision のディスカッションで私の例を参照してください。これを避けるために、コンパイラは関数呼び出し時にコードを追加する必要があります。これは -fstack-check
で実行できます GCC 用 (詳細については、Ian Lance Taylor の返信と GCC のマニュアル ページを参照してください)。
Linux カーネル 4.2
- mm/mmap.c#acct_stack_growth は、segfault するかどうかを決定します。
rlim[RLIMIT_STACK]
を使用しています これは POSIXgerlimit(RLIMIT_STACK)
に対応します - arch/x86/mm/fault.c#do_page_fault は、最終的に
acct_stack_growth
を呼び出すチェーンを開始する割り込みハンドラです。 - arch/x86/entry/entry_64.S は、ページ フォールト ハンドラを設定します。その部分を理解するには、ページングについて少し知っておく必要があります:x86 ページングはどのように機能しますか? | |スタック オーバーフロー
最小限のテスト プログラム
次に、最小限の NASM 64 ビット プログラムでテストします。
global _start
_start:
sub rsp, 0x7FF000
mov [rsp], rax
mov rax, 60
mov rdi, 0
syscall
ASLR をオフにして、環境変数を削除してください。これらはスタックに置かれてスペースを占有します:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
env -i ./main.out
制限は私の ulimit -s
をわずかに下回っています (私にとっては8MiB)。これは、環境に加えて最初にスタックに置かれた追加の System V 指定データが原因のようです。スタック オーバーフロー
本気ならTODOでスタックトップから書き始めてダウンする最小限のinitrdイメージを作ってQEMU+GDBで実行する。 dprintf
を入れる スタックアドレスを出力するループ、および acct_stack_growth
のブレークポイント .輝かしいものになるでしょう。
関連:
- https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
- Linux プロセスのスタック メモリはどこから割り当てられますか? | |スタック オーバーフロー
- Linux スタックとは? | |スタック オーバーフロー
- Python の最大再帰深度とは?それを増やす方法は?スタック オーバーフローについて
デフォルトでは、最大スタック サイズはプロセスごとに 8MB に設定されています。
ulimit
を使用して変更できます :
デフォルトを kB で表示:
$ ulimit -s
8192
無制限に設定:
ulimit -s unlimited
現在のシェルとサブシェル、およびそれらの子プロセスに影響を与えます。
(ulimit
はシェル組み込みコマンドです)
使用中の実際のスタックアドレス範囲を表示するには:
cat /proc/$PID/maps | grep -F '[stack]'