Batas tumpukan

10

Baru-baru ini saya telah menguji batas tumpukan pada tiga perangkat dengan OS yang berbeda (berdasarkan batas, maksud saya jumlah maksimum tingkat yang dimiliki tumpukan itu), dan saya perhatikan bahwa setiap kali saya menekan 2 ^ 16 level itu memberi saya kesalahan overflow, dan ketika saya meletakkan 2 ^ 16-1 itu berfungsi dengan baik.

Jadi pertanyaan saya adalah - apakah itu benar? Apakah stack memiliki batas maksimum 2 ^ 16-1 menurut definisi atau tergantung pada OS?

Anonimus
sumber
5
here i mean by limit the maximum number of levels that can the stack haveapa levelnya?
tkausl
3
Bagaimana Anda mengujinya? Apakah Anda menggunakan input 2-byte (kata)?
pro3carp3
6
Bahasa pemrograman mana yang Anda gunakan? Batasan yang tajam pada angka tetap menunjukkan bahwa itu adalah batasan yang disengaja oleh runtime spesifik bahasa Anda dan bukan oleh ukuran tumpukan yang dialokasikan OS. Misalnya python tampaknya menerapkan batas 1000 secara default untuk mencegah Anda mengenai overflow stack nyata (memulihkan dari overflow stack nyata itu sulit)
CodesInChaos

Jawaban:

20

Ini sangat spesifik untuk sistem operasi (& komputer tertentu) dan pada beberapa OS Anda memiliki beberapa cara untuk mengkonfigurasi (dan bahkan meningkatkan) batasnya. Itu bahkan kompiler spesifik (atau spesifik implementasi bahasa pemrograman Anda), karena beberapa kompiler (termasuk GCC terbaru untuk beberapa jenis kode C terbatas ) dapat mengoptimalkan beberapa panggilan ekor .

(beberapa spesifikasi bahasa pemrograman memerlukan optimasi panggilan ekor, misalnya R5RS )

Saya tidak yakin pertanyaan Anda masuk akal (dan tentu saja bukan batas 2 16 ). Di desktop Linux saya (Debian / Sid / x86-64, Linux 4.9 kernel, 32Gb RAM, Intel i5-4690S), saya mungkin memiliki tumpukan panggilan hingga 8 megabyte (dan saya dapat meningkatkan batas itu, jika saya benar-benar ingin ).

Multi-threading dan ASLR membuat pertanyaan Anda jauh lebih kompleks . Lihat misalnya pthread_attr_setstack (3) . Baca juga tentang tumpukan tumpukan (sering digunakan oleh implementasi Go ) dan tentang gaya meneruskan kelanjutan . Lihat juga jawaban ini .

Untuk apa nilainya, saya hanya mencoba kode C99 berikut (dan juga C11):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void recfun(int x, int d) {
  printf("start recfun x=%d d=%d\n", x, d);
  fflush(NULL);
  if (d>0)
    recfun(x+1, d-1);
  printf("end recfun x=%d d=%d\n", x, d);
}

int main(int argc, char**argv) {
  int md = argc>1?atoi(argv[1]):10000;
  printf ("start md=%d\n", md);
  recfun(0, md);
  printf("end md=%d clock=%ld µs\n", md, clock());
}    
// eof recur.c

dan saya bisa menjalankan recurprogram itu (dikompilasi dengan GCC 6 as gcc -Wall -O recur.c -o recur) sebanyak recur 161000 (jauh di atas batas 2 16 Anda ). Dengan recur 256000itu juga berhasil. Dengan recur 456000itu jatuh (dengan stack overflow untuk level x=272057). Saya tidak memiliki kesabaran untuk tes lain. Coba itu di komputer Anda. Jangan lupa untuk meminta optimasi.

Aturan praktis (untuk desktop, laptop, tablet) mungkin untuk menjaga tumpukan panggilan Anda di bawah satu megabyte.

Dengan meneruskan juga -fstack-usage ke gcc saya mendapatkan recur.sufile berikut (jumlahnya dalam byte, konsisten dengan intuisi batas 8Mb saya; jangan lupa mainframe panggilan, dan yang lebih penting tata letak tumpukan awal, dipasang oleh kernel saat melakukan eksekusi (2 ) ..., untuk crt0 ):

 recur.c:5:10:recfun    32  static
 recur.c:13:9:main  16  static

PS. Arduino saya memiliki Atmega328 dengan hanya 2Kbytes RAM, jadi tentu saja tidak bisa berulang sebanyak itu. Saya kira hanya beberapa ratus tumpukan bingkai yang paling mungkin di Arduinos.

Basile Starynkevitch
sumber
3

Ukuran tumpukan untuk utas utama suatu proses Windows diatur oleh tautan. Standarnya adalah 1MB tetapi dapat disesuaikan dengan sakelar / STACK. Utas yang dibuat nanti dapat menggunakan parameter dwStackSize dari fungsi CreateThread.

Jadi .. jika Anda menguji berbagai OS Windows, mereka semua memiliki ukuran stack standar yang sama sejak setidaknya NT4.0.

Eric
sumber