Tampaknya batas memori tumpukan tidak dialokasikan (toh, tidak bisa dengan tumpukan tidak terbatas). https://www.kernel.org/doc/Documentation/vm/overcommit-accounting berkata:
Pertumbuhan tumpukan bahasa C melakukan mremap implisit. Jika Anda menginginkan jaminan mutlak dan berlari mendekati tepi, Anda HARUS memetakan tumpukan Anda untuk ukuran terbesar yang menurut Anda akan Anda perlukan. Untuk penggunaan tumpukan biasa, ini tidak terlalu menjadi masalah, tetapi ini adalah kasus sudut jika Anda benar-benar peduli
Namun memetakan tumpukan akan menjadi tujuan kompiler (jika ada opsi untuk itu).
EDIT:Setelah beberapa pengujian pada mesin Debian x84_64, saya menemukan bahwa tumpukan tumbuh tanpa panggilan sistem apa pun (menurut strace
). Jadi, ini berarti kernel menumbuhkannya secara otomatis (inilah arti "implisit" di atas), yaitu tanpa mmap
eksplisit /mremap
dari proses.
Cukup sulit untuk menemukan informasi rinci yang mengkonfirmasi hal ini. Saya merekomendasikan Memahami Manajer Memori Virtual Linux oleh Mel Gorman. Saya kira jawabannya ada di Bagian 4.6.1 Menangani Kesalahan Halaman , dengan pengecualian "Wilayah tidak valid tetapi berada di samping wilayah yang dapat diperluas seperti tumpukan" dan tindakan terkait "Perluas wilayah dan alokasikan halaman". Lihat juga D.5.2 Memperluas Tumpukan .
Referensi lain tentang manajemen memori Linux (tetapi hampir tidak ada tentang tumpukan):
- FAQ Memori
- Yang harus diketahui setiap pemrogram tentang memori oleh Ulrich Drepper
EDIT 2:Implementasi ini memiliki kelemahan:dalam kasus sudut, tabrakan tumpukan-tumpukan mungkin tidak terdeteksi, bahkan dalam kasus di mana tumpukan akan lebih besar dari batas! Alasannya adalah bahwa penulisan dalam variabel di tumpukan mungkin berakhir di memori tumpukan yang dialokasikan, dalam hal ini tidak ada kesalahan halaman dan kernel tidak dapat mengetahui bahwa tumpukan perlu diperpanjang. Lihat contoh saya di diskusi Tabrakan tumpukan-tumpukan senyap di bawah GNU/Linux yang saya mulai di daftar bantuan gcc. Untuk menghindarinya, kompiler perlu menambahkan beberapa kode pada pemanggilan fungsi; ini dapat dilakukan dengan -fstack-check
untuk GCC (lihat balasan Ian Lance Taylor dan halaman manual GCC untuk detailnya).
Linux kernel 4.2
- mm/mmap.c#acct_stack_growth memutuskan apakah akan segfault atau tidak. Ini menggunakan
rlim[RLIMIT_STACK]
yang sesuai dengan POSIXgerlimit(RLIMIT_STACK)
- arch/x86/mm/fault.c#do_page_fault adalah penangan interupsi yang memulai rangkaian yang akhirnya memanggil
acct_stack_growth
- arch/x86/entry/entry_64.S menyiapkan penangan kesalahan halaman. Anda perlu tahu sedikit tentang paging untuk memahami bagian itu:Bagaimana cara kerja paging x86? | Stack Overflow
Program uji minimal
Kami kemudian dapat mengujinya dengan program NASM 64-bit minimal:
global _start
_start:
sub rsp, 0x7FF000
mov [rsp], rax
mov rax, 60
mov rdi, 0
syscall
Pastikan Anda menonaktifkan ASLR dan menghapus variabel lingkungan karena akan masuk ke tumpukan dan menghabiskan ruang:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
env -i ./main.out
Batasnya sedikit di bawah ulimit -s
saya (8MiB untuk saya). Sepertinya ini karena data tambahan yang ditentukan System V awalnya diletakkan di tumpukan selain lingkungan:parameter baris perintah Linux 64 di Assembly | Stack Overflow
Jika Anda serius tentang ini, TODO membuat gambar initrd minimal yang mulai menulis dari tumpukan paling atas dan turun, lalu menjalankannya dengan QEMU + GDB. Letakkan dprintf
pada loop mencetak alamat stack, dan breakpoint di acct_stack_growth
. Itu akan menjadi mulia.
Terkait:
- https://softwareengineering.stackexchange.com/questions/207386/how-are-the-size-of-the-stack-and-heap-limited-by-the-os
- Dari mana memori tumpukan dialokasikan untuk proses Linux? | Stack Overflow
- Apa yang dimaksud dengan Tumpukan Linux? | Stack Overflow
- Berapa kedalaman rekursi maksimum di Python, dan bagaimana cara meningkatkannya? di Stack Overflow
Secara default, ukuran tumpukan maksimal dikonfigurasi menjadi 8MB per proses,
tetapi dapat diubah menggunakan ulimit
:
Menampilkan default di kB:
$ ulimit -s
8192
Setel ke tidak terbatas:
ulimit -s unlimited
mempengaruhi shell dan subkulit saat ini dan proses anaknya.
(ulimit
adalah perintah bawaan Shell)
Anda dapat menampilkan rentang alamat tumpukan aktual yang digunakan dengan:
cat /proc/$PID/maps | grep -F '[stack]'
di Linux.