Berapa banyak penggunaan tumpukan terlalu banyak?

22

Akhir-akhir ini ketika saya sedang menulis C atau C ++, saya akan mendeklarasikan semua variabel saya di stack hanya karena itu pilihan, tidak seperti dengan Java.

Namun, saya pernah mendengar bahwa itu adalah ide yang buruk untuk menyatakan hal-hal besar di tumpukan.

  1. Kenapa ini yang terjadi? Saya pikir stack overflow terlibat, tapi saya tidak begitu jelas mengapa itu terjadi.
  2. Berapa banyak barang di tumpukan yang terlalu banyak?

Saya tidak mencoba untuk meletakkan file 100MB di stack, hanya selusin kilobyte array untuk digunakan sebagai buffer string atau apa pun. Apakah ini terlalu banyak penggunaan stack?

(Maaf jika duplikat, mencari stack terus memberikan referensi ke Stack Overflow. Bahkan tidak ada tag stack panggilan, saya hanya menggunakan yang abstrak.)

Elliot Way
sumber
1
Bagaimana Anda "meletakkan file 100MB di tumpukan"? Implementasi buffer dan container (dan sejenisnya seperti std :: string) biasanya menggunakan heap untuk menyimpan payload mereka.
Murphy
2
Anda dapat menggunakan cukup banyak penggunaan tumpukan per fungsi / metode sampai rekursi terlibat, maka Anda berisiko sangat membatasi kemampuan Anda, vis-à-vis kedalaman rekursif, sehingga dalam fungsi rekursif, Anda ingin menggunakan sedikit lokal ruang variabel / stack mungkin.
Erik Eidt
3
Perhatikan bahwa C&C ++ berbeda. std::vector<int>Variabel lokal tidak akan memakan banyak ruang stack, sebagian besar data berada di tumpukan.
Basile Starynkevitch

Jawaban:

18

Itu tergantung pada sistem operasi Anda. Pada Windows, ukuran maksimum tipikal untuk stack adalah 1MB, sedangkan itu adalah 8MB pada Linux modern yang khas, meskipun nilai-nilai tersebut dapat disesuaikan dengan berbagai cara. Jika jumlah variabel stack Anda (termasuk overhead level rendah seperti alamat pengirim, argumen berbasis stack, placeholder nilai balik, dan byte penyelarasan) di seluruh tumpukan panggilan melebihi batas itu, Anda mendapatkan stack overflow, yang biasanya membuat Anda kehilangan Program tanpa peluang pemulihan.

Beberapa kilobyte biasanya baik-baik saja. Puluhan kilobyte berbahaya karena mulai meringkas. Ratusan kilobyte adalah ide yang sangat buruk.

Sebastian Redl
sumber
1
Bukankah tumpukan tipikal membatasi beberapa megabyte (yaitu biasanya lebih dari satu, tetapi mungkin kurang dari selusin) hari ini di 2016? Di desktop Linux saya, defaultnya adalah 8Mbytes ...
Basile Starynkevitch
"Pada [...] Linux, ukuran maksimum tipikal untuk stack adalah 1MB" $ ulimit -apada sistem saya kembali antara lain stack size (kbytes, -s) 8192.
Murphy
9

Satu-satunya jawaban yang valid tidak jelas: "terlalu banyak adalah ketika tumpukan meluap."

Kecuali Anda memiliki kendali penuh atas implementasi setiap baris kode antara titik masuk program dan fungsi yang dimaksud, Anda tidak dapat membuat asumsi tentang berapa banyak tumpukan yang tersedia. Anda tidak dapat, misalnya, menjamin bahwa memanggil fungsi ini tidak akan pernah menyebabkan stack overflow:

void break_the_camels_back()
{
    int straw;
    ...
}

Stack 8 MiB default pada Unix modern cukup banyak ruang untuk tumpukan, terutama untuk orang seperti saya yang cukup tua untuk mengingat CPU dengan pointer stack 8-bit. Kenyataan praktisnya adalah bahwa Anda tidak mungkin menerobosnya tanpa mencoba. Jika Anda melakukannya, melebihi batas tumpukan biasanya dianggap sebagai pelanggaran segmentasi, dan sistem dengan manajemen memori yang cukup untuk mendeteksinya akan mengirimkan SIGSEGVketika terjadi.

Anda memiliki beberapa opsi. Pertama adalah untuk tidak menebak berapa banyak tumpukan tersedia dan tanyakan sistem. Apa pun yang sesuai dengan POSIX akan memiliki getrlimit(2)fungsi yang akan memberi tahu Anda batas atas. RLIMIT_STACKadalah batas spesifik yang Anda inginkan. Yang kedua adalah untuk memantau seberapa banyak tumpukan program Anda gunakan dan membuat keputusan tentang variabel otomatis vs alokasi memori dinamis berdasarkan itu. Sejauh yang saya tahu, tidak ada fungsi standar untuk menentukan berapa banyak tumpukan yang digunakan, tetapi program seperti itu valgrinddapat menganalisisnya untuk Anda.

Blrfl
sumber
4

Jika Anda mengalokasikan array yang mengatakan 10.000 byte pada stack, maka ukuran array tersebut terbatas. 10.000 mungkin banyak, tetapi jika Anda membutuhkan 10.001 byte maka program Anda bisa macet atau lebih buruk. Jadi dalam situasi ini, Anda menginginkan sesuatu yang menyesuaikan dengan ukuran yang Anda butuhkan, dan sesuatu itu tidak ada di tumpukan.

Array ukuran tetap untuk buffer string pada stack tidak menjadi masalah karena mereka menyimpan memori pada stack, mereka adalah masalah karena buffer ukuran tetap adalah masalah fatal yang menunggu untuk terjadi.

Tetapi jika Anda menggunakan C ++, dan mendeklarasikan misalnya std :: string atau std :: vec pada stack, maka apa yang ada di stack sebenarnya adalah ukuran tetap dan kecil. Data aktual akan disimpan di heap. Anda dapat menyimpan satu juta karakter dalam contoh std :: string, dan hanya akan mengambil sejumlah kecil data (biasanya 8 hingga 24 byte, tergantung pada implementasinya) pada stack, dan satu juta byte pada heap.

gnasher729
sumber
2

Nah 1 MB adalah perkiraan yang bagus untuk * nix. Rekursi mungkin menjadi alasan utama stack overflow dalam kombinasi dengan alokasi stack. Namun, dalam banyak kasus objek dewa yang dangkal tampak terlalu besar untuk ditempatkan di stack dirancang dengan baik untuk mengelola memori internal mereka di heap dan menggunakan stack hanya sebagai cara untuk secara otomatis dihancurkan ketika stack muncul. Destruktor akan membebaskan potongan besar memori yang dikelola secara internal. Wadah std dirancang dengan cara itu, dan pointer bersama / unik dirancang seperti itu juga.

Yang penting adalah untuk tidak mengalokasikan potongan besar dari mem mentah pada stack seperti char [1024 * 1024] dan untuk merancang kelas untuk membungkus alokasi heap dan menggunakan stack hanya untuk kenyamanan memanggil pemusnah secara otomatis.

Asterisk
sumber