Ostatnio, gdy piszę C lub C ++, zadeklaruję wszystkie moje zmienne na stosie tylko dlatego, że jest to opcja, w przeciwieństwie do Javy.
Jednak słyszałem, że deklarowanie dużych rzeczy na stosie jest złym pomysłem.
- Dlaczego dokładnie tak jest w tym przypadku? Sądzę, że w grę wchodzi przepełnienie stosu, ale nie bardzo wiem, dlaczego tak się dzieje.
- Ile rzeczy na stosie to za dużo?
Nie próbuję umieszczać 100 MB plików na stosie, tylko kilkanaście kilobajtów tablic do wykorzystania jako bufory łańcuchów lub cokolwiek innego. Czy to zbyt duże zużycie stosu?
(Przepraszam, jeśli zduplikowane, wyszukiwanie stosu wciąż zawiera odniesienia do Przepełnienia stosu. Nie ma nawet znacznika stosu wywołań, po prostu użyłem abstrakcyjnego).
stack
memory-usage
stackoverflow
Elliot Way
źródło
źródło
std::vector<int>
Zmienna lokalna nie zje dużo miejsca na stosie, ponieważ większość danych jest w stercie.Odpowiedzi:
To zależy od twojego systemu operacyjnego. W systemie Windows typowy maksymalny rozmiar stosu wynosi 1 MB, podczas gdy w typowym nowoczesnym systemie Linux jest to 8 MB, chociaż wartości te można regulować na różne sposoby. Jeśli suma zmiennych stosu (w tym narzut niskiego poziomu, takich jak adresy zwrotne, argumenty oparte na stosie, symbole zastępcze wartości zwracanej i bajty wyrównania) w całym stosie wywołań przekracza ten limit, otrzymasz przepełnienie stosu, co zwykle zmniejsza program bez szans na odzyskanie.
Kilka kilobajtów jest zwykle w porządku. Dziesiątki kilobajtów jest niebezpieczne, ponieważ zaczyna się sumować. Setki kilobajtów to bardzo zły pomysł.
źródło
$ ulimit -a
w moim systemie zwraca między innymistack size (kbytes, -s) 8192
.Jedyną prawidłową odpowiedzią jest niejasna: „za dużo jest, gdy stos się przepełnia”.
O ile nie masz pełnej kontroli nad implementacją każdego wiersza kodu między punktem wejścia programu a funkcją, o której mowa, nie możesz przyjmować żadnych założeń dotyczących ilości dostępnego stosu. Nie można na przykład zagwarantować, że wywołanie tej funkcji nigdy nie spowoduje przepełnienia stosu:
Domyślny stos 8 MiB we współczesnych Uniksach to dość dużo miejsca w stosach, szczególnie dla kogoś takiego jak ja, który ma dość geezera, aby zapamiętać procesory z 8-bitowymi wskaźnikami stosu. Praktyczna rzeczywistość jest taka, że prawdopodobnie nie przebijesz jej bez próby. Jeśli to zrobisz, przekroczenie limitu stosu jest zwykle uważane za naruszenie segmentacji, a systemy z wystarczającym zarządzaniem pamięcią do wykrycia go wyślą
SIGSEGV
gdy to nastąpi.Masz kilka opcji. Po pierwsze, nie zgadnij, ile stosu jest dostępnych i zapytaj system. Wszystko zgodne z POSIX będzie miało
getrlimit(2)
funkcję, która powie ci górną granicę.RLIMIT_STACK
to konkretny limit, jaki chcesz. Drugim jest monitorowanie, ile stosu używają twoje programy, i podejmowanie decyzji dotyczących zmiennych automatycznych w porównaniu do dynamicznej alokacji pamięci na tej podstawie. O ile mi wiadomo, nie ma standardowych funkcji określających, ile stosu jest używany, ale programy takievalgrind
mogą go dla ciebie przeanalizować.źródło
Jeśli przydzielisz tablicę powiedzmy 10 000 bajtów na stosie, rozmiar tej tablicy jest ograniczony. 10 000 może być dużo, ale jeśli potrzebujesz 10 001 bajtów, Twój program może ulec awarii lub gorzej. Więc w tej sytuacji potrzebujesz czegoś, co dostosuje się do potrzebnego rozmiaru i że czegoś nie będzie na stosie.
Tablice o stałych rozmiarach dla buforów łańcuchowych na stosie nie stanowią problemu, ponieważ utrzymują pamięć na stosie, są problemem, ponieważ bufory o stałych rozmiarach są śmiertelnym problemem, który czeka.
Ale jeśli użyjesz C ++ i zadeklarujesz na stosie std :: string lub std :: vec na stosie, wówczas to, co znajduje się na stosie, będzie miało rzeczywiście stały i mały rozmiar. Rzeczywiste dane będą przechowywane na stercie. Możesz przechowywać milion znaków w instancji std :: string i zajmie to bardzo niewielką ilość danych (zwykle 8 do 24 bajtów, w zależności od implementacji) na stosie i milion bajtów na stercie.
źródło
Cóż, 1 MB to dobry szacunek dla * nix. Rekurencja może być głównym powodem przepełnienia stosu w połączeniu z przydziałami stosu. Jednak w większości przypadków boskie obiekty, które pozornie wydają się zbyt duże, aby mogły zostać umieszczone na stosie, są dobrze zaprojektowane do zarządzania pamięcią wewnętrzną na stosie i używają stosu tylko jako sposobu na automatyczne zniszczenie, gdy stos zostanie zdjęty. Destruktor uwolni ogromne fragmenty pamięci zarządzanej wewnętrznie. Kontenery standardowe są zaprojektowane w ten sposób, a wspólne / unikalne wskaźniki również są zaprojektowane w ten sposób.
Ważne jest, aby nie przydzielać dużych porcji surowej pamięci na stosie, takich jak char [1024 * 1024], i projektować klasy, które będą zawijać przydziały stosów i używać stosu tylko dla wygody automatycznego wywoływania destruktora.
źródło