Odwróć swoje pytanie. Prawdziwe motywujące pytanie brzmi: w jakich okolicznościach możemy uniknąć kosztów wywozu śmieci?
Po pierwsze, jakie są koszty wywozu śmieci? Istnieją dwa główne koszty. Najpierw musisz ustalić, co żyje ; co wymaga potencjalnie dużo pracy. Po drugie, musisz zagęścić dziury , które powstają, gdy uwolnisz coś, co zostało podzielone na dwie żywe rzeczy. Te dziury są marnotrawstwem. Ale ich kompaktowanie jest również drogie.
Jak możemy uniknąć tych kosztów?
Oczywiście, jeśli możesz znaleźć wzorzec użycia pamięci, w którym nigdy nie przydzielasz czegoś długowiecznego, a następnie przydzielasz coś krótkotrwałego, a następnie przydzielasz coś długowiecznego, możesz wyeliminować koszt dziur. Jeśli możesz zagwarantować, że w przypadku niektórych podzbiorów magazynu każdy kolejny przydział jest krótszy niż poprzedni w tym magazynie, nigdy nie będzie żadnych dziur w tym magazynie.
Ale jeśli rozwiązaliśmy problem dziury, to rozwiązaliśmy również problem usuwania śmieci . Czy masz coś w tym magazynie, który wciąż żyje? Tak. Czy wszystko zostało przydzielone, zanim trwało dłużej? Tak - to założenie eliminuje możliwość powstawania dziur. Dlatego wszystko, co musisz zrobić, to powiedzieć „czy ostatnia alokacja jest aktualna?” i wiesz, że wszystko żyje w tym magazynie.
Czy mamy zestaw przydziałów pamięci, w którym wiemy, że każdy kolejny przydział jest krótszy niż poprzedni? Tak! Ramki aktywacyjne metod są zawsze niszczone w odwrotnej kolejności niż zostały utworzone, ponieważ są one zawsze krótsze niż aktywacja, która je utworzyła.
Dlatego możemy przechowywać ramki aktywacyjne na stosie i wiedzieć, że nigdy nie trzeba ich zbierać. Jeśli na stosie jest jakaś ramka, cały zestaw ramek pod nią jest dłuższy, więc nie trzeba ich zbierać. I zostaną zniszczone w odwrotnej kolejności niż zostały stworzone. Koszt zbierania śmieci jest w ten sposób wyeliminowany dla ramek aktywacyjnych.
Właśnie dlatego mamy tymczasową pulę na stosie: ponieważ jest to prosty sposób na wdrożenie aktywacji metody bez ponoszenia kary za zarządzanie pamięcią.
(Oczywiście koszt wyrzucania śmieci do pamięci, o którym mowa w odnośnikach do ramek aktywacyjnych, nadal istnieje).
Rozważmy teraz system kontroli przepływu, w którym ramki aktywacyjne nie są niszczone w przewidywalnej kolejności. Co się stanie, jeśli aktywacja krótkotrwała może spowodować aktywację długoterminową? Jak możesz sobie wyobrazić, na tym świecie nie możesz już używać stosu do optymalizacji potrzeby zbierania aktywacji. Zestaw aktywacji może ponownie zawierać dziury.
C # 2.0 ma tę funkcję w postaci yield return
. Metoda, która zwraca zysk, zostanie ponownie aktywowana w późniejszym czasie - przy następnym wywołaniu MoveNext - a kiedy tak się stanie, nie jest przewidywalna. W związku z tym informacje, które normalnie byłyby na stosie dla ramki aktywacyjnej bloku iteratora, są zamiast tego przechowywane na stercie, gdzie są gromadzone śmieci po zebraniu modułu wyliczającego.
Podobnie funkcja „asynchronizuj / czekaj” pojawiająca się w następnych wersjach C # i VB pozwoli ci tworzyć metody, których aktywacje „dają” i „wznawiają” w ściśle określonych punktach podczas działania metody. Ponieważ ramki aktywacyjne nie są już tworzone i niszczone w przewidywalny sposób, wszystkie informacje, które były przechowywane na stosie, będą musiały być przechowywane na stosie.
To tylko przypadek historii, że przez kilka dziesięcioleci zdecydowaliśmy, że języki z ramkami aktywacyjnymi, które są tworzone i niszczone w ściśle uporządkowany sposób, są modne. Ponieważ współczesne języki w coraz większym stopniu nie mają tej właściwości, należy spodziewać się, że coraz więcej języków będzie potwierdzało kontynuację na stosie śmieci, a nie stosie.