W skrócie
Stos jest używany do statycznej alokacji pamięci, a sterty do dynamicznej alokacji pamięci, obie przechowywane w pamięci RAM komputera.
Szczegółowo
Stos
Stos jest strukturą danych „LIFO” (ostatnie wejście, pierwsze wyjście), którą procesor dość dokładnie zarządza i optymalizuje. Za każdym razem, gdy funkcja deklaruje nową zmienną, jest „wypychana” na stos. Następnie przy każdym wyjściu funkcji wszystkie zmienne wypychane na stos przez tę funkcję są zwalniane (to znaczy są usuwane). Po zwolnieniu zmiennej stosu ten obszar pamięci staje się dostępny dla innych zmiennych stosu.
Zaletą używania stosu do przechowywania zmiennych jest to, że pamięć jest zarządzana za Ciebie. Nie musisz ręcznie przydzielać pamięci ani jej zwalniać, gdy już jej nie potrzebujesz. Co więcej, ponieważ procesor tak skutecznie organizuje pamięć stosu, odczytywanie i zapisywanie zmiennych stosu jest bardzo szybkie.
Więcej można znaleźć tutaj .
Kupa
Sterta to obszar pamięci komputera, który nie jest dla ciebie zarządzany automatycznie i nie jest tak ściśle zarządzany przez procesor. Jest to bardziej swobodny obszar pamięci (i jest większy). Aby przydzielić pamięć na stercie, musisz użyć malloc () lub calloc (), które są wbudowanymi funkcjami C. Po przydzieleniu pamięci na stercie jesteś odpowiedzialny za użycie free () w celu zwolnienia pamięci, gdy już jej nie potrzebujesz.
Jeśli tego nie zrobisz, w twoim programie wystąpi wyciek pamięci. Oznacza to, że pamięć na stercie nadal będzie odłożona na bok (i nie będzie dostępna dla innych procesów). Jak zobaczymy w sekcji debugowania, istnieje narzędzie o nazwie Valgrind, które może pomóc w wykryciu wycieków pamięci.
W przeciwieństwie do stosu, sterta nie ma ograniczeń wielkości zmiennych (oprócz oczywistych fizycznych ograniczeń komputera). Pamięć sterty jest nieco wolniejsza do odczytu i zapisu, ponieważ należy użyć wskaźników, aby uzyskać dostęp do pamięci na stercie. Niedługo porozmawiamy o wskaźnikach.
W przeciwieństwie do stosu, zmienne utworzone na stercie są dostępne dla dowolnej funkcji w dowolnym miejscu programu. Zmienne sterty mają zasadniczo zasięg globalny.
Więcej można znaleźć tutaj .
Zmienne przydzielone na stosie są przechowywane bezpośrednio w pamięci, a dostęp do tej pamięci jest bardzo szybki, a jej przydzielanie jest obsługiwane podczas kompilacji programu. Gdy funkcja lub metoda wywołuje inną funkcję, która z kolei wywołuje inną funkcję itp., Wykonywanie wszystkich tych funkcji pozostaje zawieszone, dopóki ostatnia funkcja nie zwróci swojej wartości. Stos jest zawsze zarezerwowany w kolejności LIFO, ostatnio zarezerwowany blok jest zawsze następnym blokiem do zwolnienia. To sprawia, że śledzenie stosu jest naprawdę proste, uwolnienie bloku ze stosu to nic innego jak dostosowanie jednego wskaźnika.
Zmienne przydzielone na stercie mają przydzieloną pamięć w czasie wykonywania, a dostęp do tej pamięci jest nieco wolniejszy, ale wielkość sterty jest ograniczona tylko rozmiarem pamięci wirtualnej. Elementy stosu nie są od siebie zależne i zawsze można uzyskać do nich dostęp losowo w dowolnym momencie. Możesz przydzielić blok w dowolnym momencie i zwolnić go w dowolnym momencie. To znacznie komplikuje śledzenie, które części sterty są przydzielane lub wolne w danym momencie.
Możesz użyć stosu, jeśli dokładnie wiesz, ile danych musisz przydzielić przed czasem kompilacji, i nie jest on zbyt duży. Możesz użyć sterty, jeśli nie wiesz dokładnie, ile danych będziesz potrzebować w czasie wykonywania lub jeśli musisz przydzielić dużo danych.
W sytuacji wielowątkowej każdy wątek będzie miał swój własny, całkowicie niezależny stos, ale będzie dzielił stertę. Stos jest zależny od wątku, a sterta jest zależna od aplikacji. Stos należy wziąć pod uwagę podczas obsługi wyjątków i wykonywania wątków.
Każdy wątek otrzymuje stos, podczas gdy zazwyczaj aplikacja ma tylko jedną stertę (chociaż nierzadko jest mieć wiele stosów dla różnych rodzajów alokacji).
W czasie wykonywania, jeśli aplikacja potrzebuje więcej sterty, może przydzielić pamięć z wolnej pamięci, a jeśli stos potrzebuje pamięci, może przydzielić pamięć z wolnej pamięci przydzielonej dla aplikacji.
Nawet więcej szczegółów podano tutaj i tutaj .
Teraz przyjdź do odpowiedzi na twoje pytanie .
W jakim stopniu są one kontrolowane przez system operacyjny lub środowisko uruchomieniowe języka?
System operacyjny przydziela stos dla każdego wątku na poziomie systemu podczas tworzenia wątku. Zazwyczaj system operacyjny jest wywoływany przez środowisko wykonawcze języka w celu przydzielenia sterty dla aplikacji.
Więcej można znaleźć tutaj .
Jaki jest ich zakres?
Już podane w górę.
„Możesz użyć stosu, jeśli dokładnie wiesz, ile danych musisz przeznaczyć przed czasem kompilacji, i nie jest on zbyt duży. Możesz użyć stosu, jeśli nie wiesz dokładnie, ile danych będziesz potrzebować w czasie wykonywania lub jeśli musisz przydzielić dużo danych ”.
Więcej można znaleźć tutaj .
Co decyduje o wielkości każdego z nich?
Rozmiar stosu jest ustalany przez system operacyjny podczas tworzenia wątku. Rozmiar sterty jest ustawiany podczas uruchamiania aplikacji, ale może rosnąć w miarę potrzebnego miejsca (alokator żąda więcej pamięci z systemu operacyjnego).
Co przyspiesza?
Alokacja stosu jest znacznie szybsza, ponieważ tak naprawdę wszystko przesuwa wskaźnik stosu. Korzystając z pul pamięci, można uzyskać porównywalną wydajność dzięki alokacji sterty, ale wiąże się to z niewielką dodatkową złożonością i własnymi problemami.
Ponadto stos kontra stos to nie tylko kwestia wydajności; mówi również wiele o oczekiwanym okresie użytkowania obiektów.
Szczegóły można znaleźć tutaj .