Kiedy alokujesz pamięć na stercie, jedynym ograniczeniem jest wolna pamięć RAM (lub pamięć wirtualna). To sprawia, że Gb pamięci.
Dlaczego więc rozmiar stosu jest tak ograniczony (około 1 Mb)? Jaki powód techniczny uniemożliwia tworzenie naprawdę dużych obiektów na stosie?
Aktualizacja : Mój zamiar może nie być jasny, nie chcę umieszczać dużych obiektów na stosie i nie potrzebuję większego stosu. To pytanie to po prostu czysta ciekawość.
c++
memory-management
undu
źródło
źródło
Odpowiedzi:
Moja intuicja jest następująca. Stos nie jest tak łatwy do zarządzania jak sterta. Stos musi być przechowywany w ciągłych lokalizacjach pamięci. Oznacza to, że nie możesz losowo przydzielać stosu w razie potrzeby, ale musisz przynajmniej zarezerwować w tym celu adresy wirtualne. Im większy rozmiar zarezerwowanej wirtualnej przestrzeni adresowej, tym mniej wątków można utworzyć.
Na przykład aplikacja 32-bitowa ma na ogół wirtualną przestrzeń adresową 2 GB. Oznacza to, że jeśli rozmiar stosu wynosi 2 MB (domyślnie w pthreads), możesz utworzyć maksymalnie 1024 wątki. Może to być niewielkie w przypadku aplikacji, takich jak serwery internetowe. Zwiększenie rozmiaru stosu do, powiedzmy, 100 MB (tj. Rezerwujesz 100 MB, ale niekoniecznie natychmiast przydzielasz stosowi 100 MB), ograniczyłoby liczbę wątków do około 20, co może być ograniczeniem nawet dla prostych aplikacji GUI.
Ciekawym pytaniem jest, dlaczego nadal mamy ten limit na platformach 64-bitowych. Nie znam odpowiedzi, ale zakładam, że ludzie są już przyzwyczajeni do pewnych „dobrych praktyk stosu”: uważaj, aby alokować ogromne obiekty na stercie i, jeśli to konieczne, ręcznie zwiększaj rozmiar stosu. Dlatego nikt nie uznał za przydatne dodawanie obsługi „ogromnego” stosu na platformach 64-bitowych.
źródło
Jeden aspekt, o którym nikt jeszcze nie wspomniał:
Ograniczony rozmiar stosu to mechanizm wykrywania i powstrzymywania błędów.
Zasadniczo głównym zadaniem stosu w C i C ++ jest śledzenie stosu wywołań i zmiennych lokalnych, a jeśli stos wyrasta poza granice, prawie zawsze jest to błąd w projekcie i / lub zachowaniu aplikacji .
Gdyby zezwolono na arbitralny wzrost stosu, te błędy (jak nieskończona rekurencja) byłyby wychwytywane bardzo późno, dopiero po wyczerpaniu zasobów systemu operacyjnego. Można temu zapobiec, ustawiając arbitralny limit rozmiaru stosu. Rzeczywisty rozmiar nie jest tak ważny, poza tym, że jest wystarczająco mały, aby zapobiec degradacji systemu.
źródło
std::unique_ptr
aby napisać destruktor (i nie polegać na inteligentnym wskaźniku)).To tylko domyślny rozmiar. Jeśli potrzebujesz więcej, możesz uzyskać więcej - najczęściej mówiąc linkerowi, aby przydzielił dodatkową przestrzeń na stosie.
Wadą dużych stosów jest to, że jeśli utworzysz wiele wątków, będą one potrzebować po jednym stosie. Jeśli wszystkie stosy przydzielają wiele MB, ale ich nie używają, miejsce zostanie zmarnowane.
Musisz znaleźć odpowiednią równowagę dla swojego programu.
Niektórzy ludzie, jak @BJovke, uważają, że pamięć wirtualna jest zasadniczo wolna. Prawdą jest, że nie musisz mieć fizycznej pamięci stanowiącej kopię zapasową całej pamięci wirtualnej. Musisz być w stanie przynajmniej podać adresy do pamięci wirtualnej.
Jednak na typowym 32-bitowym komputerze rozmiar pamięci wirtualnej jest taki sam, jak rozmiar pamięci fizycznej - ponieważ mamy tylko 32 bity na dowolny adres, wirtualny lub nie.
Ponieważ wszystkie wątki w procesie mają tę samą przestrzeń adresową, muszą ją podzielić między siebie. A kiedy system operacyjny odegrał swoją rolę, na aplikację zostało „tylko” 2-3 GB. Ten rozmiar jest ograniczeniem zarówno dla pamięci fizycznej, jak i wirtualnej, ponieważ nie ma już więcej adresów.
źródło
Po pierwsze, stos jest ciągły, więc jeśli przydzielisz 12 MB, musisz usunąć 12 MB, jeśli chcesz zejść poniżej tego, co utworzyłeś. Również poruszanie się wokół obiektów staje się znacznie trudniejsze. Oto przykład z prawdziwego świata, który może ułatwić zrozumienie:
Powiedzmy, że układasz pudełka w całym pokoju. Które jest łatwiejsze w zarządzaniu:
Te dwa przykłady to rażące uogólnienia i są pewne punkty, które są rażąco błędne w analogii, ale są na tyle bliskie, że miejmy nadzieję, że pomogą ci dostrzec zalety w obu przypadkach.
źródło
Pomyśl o stosie w kolejności od blisko do daleko. Rejestry są blisko procesora (szybko), stos jest nieco dalej (ale wciąż stosunkowo blisko), a sterta daleko (wolny dostęp).
Stos oczywiście znajduje się na stercie, ale mimo to, ponieważ jest używany w sposób ciągły, prawdopodobnie nigdy nie opuszcza pamięci podręcznej procesora, co czyni go szybszym niż zwykły dostęp do sterty. Jest to powód, aby utrzymywać stosy w rozsądnych rozmiarach; aby przechowywać je w pamięci podręcznej jak najwięcej. Przydzielanie obiektów z dużym stosem (prawdopodobnie automatycznie zmieniając rozmiar stosu w przypadku przepełnienia) jest sprzeczne z tą zasadą.
Jest to więc dobry paradygmat wydajności, a nie tylko pozostałość po dawnych czasach.
źródło
Wiele rzeczy, do których Twoim zdaniem potrzebujesz dużego stacka, można zrobić w inny sposób.
„Algorytmy” Sedgewicka mają kilka dobrych przykładów „usuwania” rekurencji z algorytmów rekurencyjnych, takich jak QuickSort, poprzez zastąpienie rekurencji iteracją. W rzeczywistości algorytm jest nadal rekurencyjny i nadal istnieje jako stos, ale stos sortowania jest przydzielany na stercie, zamiast używać stosu środowiska wykonawczego.
(Preferuję drugie wydanie, z algorytmami podanymi w Pascalu. Można go było użyć za osiem dolarów).
Inaczej mówiąc, jeśli myślisz, że potrzebujesz dużego stosu, twój kod jest nieefektywny. Jest lepszy sposób, który zużywa mniej stosu.
źródło
Myślę, że nie ma żadnego technicznego powodu, ale byłaby to dziwna aplikacja, która właśnie utworzyła tylko jeden ogromny super-obiekt na stosie. Obiektom stosu brakuje elastyczności, która staje się bardziej problematyczna wraz ze wzrostem rozmiaru - nie można ich powrócić bez ich zniszczenia ani ustawić w kolejce do innych wątków.
źródło
int main() { char buffer[1048576]; }
To bardzo powszechny problem dla początkujących. Jasne, że istnieje łatwe obejście, ale dlaczego powinniśmy obejść rozmiar stosu?