Co jest szybsze: alokacja stosu lub alokacja sterty

To pytanie może brzmieć dość elementarnie, ale jest to debata z innym programistą, z którym pracuję.

Dbałem o to, aby przydzielać rzeczy na stosie, gdzie tylko mogłem, zamiast przydzielać je na stosie. Rozmawiał ze mną i obserwował mnie przez ramię i skomentował, że nie było to konieczne, ponieważ są tacy sami.

Zawsze miałem wrażenie, że wzrost stosu to stały czas, a wydajność alokacji sterty zależała od prądu złożoność sterty zarówno dla alokacji (znalezienie otworu o odpowiednim rozmiarze), jak i De-alokacji (zwijanie otworów w celu zmniejszenia fragmentacji, ponieważ wiele standardowych implementacji bibliotek wymaga czasu, aby to zrobić podczas usuwania, jeśli się nie mylę).

Wydaje mi się to czymś, co prawdopodobnie byłoby bardzo zależne od kompilatora. W szczególności dla tego projektu używam kompilatora Metrowerks dla architektury PPC. Wgląd w to połączenie byłby najbardziej pomocny, ale w ogólne, dla GCC i MSVC++, o co chodzi? Czy alokacja sterty nie jest tak wydajna jak alokacja stosu? Nie ma różnicy? Czy różnice są tak małe, że staje się bezcelowa mikro-optymalizacja.

Author: dlavila, 2008-10-02

23 answers

Przydzielanie stosu jest znacznie szybsze, ponieważ wszystko, co tak naprawdę robi, to przesunięcie wskaźnika stosu. Korzystając z pul pamięci, możesz uzyskać porównywalną wydajność z alokacji sterty, ale wiąże się to z niewielką dodatkową złożonością i własnymi bólami głowy.

Ponadto, stack vs. heap jest nie tylko kwestią wydajności; mówi również wiele o oczekiwanym okresie życia obiektów.

 447
Author: Torbjörn Gyllebring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-20 01:37:07

Stack jest znacznie szybszy. Dosłownie używa tylko jednej instrukcji na większości architektur, w większości przypadków, np. na x86:

sub esp, 0x10

(przesuwa wskaźnik stosu w dół o 0x10 bajtów i tym samym "przydziela" te bajty do użycia przez zmienną.)

Oczywiście, rozmiar stosu jest bardzo, bardzo skończony, ponieważ szybko dowiesz się, czy nadużywasz alokacji stosu lub próbujesz wykonać rekursję: -)

Ponadto, nie ma powodu, aby optymalizować wydajność kodu, który nie weryfikowalne potrzebują go, takie jak wykazane przez profilowanie. "Przedwczesna optymalizacja" często powoduje więcej problemów niż jest warta.

Moja zasada: Jeśli wiem, że będę potrzebował danych w czasie kompilacji, a ich rozmiar jest mniejszy niż kilkaset bajtów, przydzielam je w stos. W przeciwnym razie Kupię go.

 154
Author: Dan Lenski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-08 12:45:19

Szczerze mówiąc, napisanie programu do porównywania wydajności jest trywialne:]}

#include <ctime>
#include <iostream>

namespace {
    class empty { }; // even empty classes take up 1 byte of space, minimum
}

int main()
{
    std::clock_t start = std::clock();
    for (int i = 0; i < 100000; ++i)
        empty e;
    std::clock_t duration = std::clock() - start;
    std::cout << "stack allocation took " << duration << " clock ticks\n";
    start = std::clock();
    for (int i = 0; i < 100000; ++i) {
        empty* e = new empty;
        delete e;
    };
    duration = std::clock() - start;
    std::cout << "heap allocation took " << duration << " clock ticks\n";
}

Mówi się, że głupia konsystencja jest hobgoblinem małych umysłów . Najwyraźniej optymalizacja kompilatorów jest hobgoblinami wielu programistów. Ta dyskusja była kiedyś na samym dole odpowiedzi, ale ludzie najwyraźniej nie mogą się martwić, że przeczytają tak daleko, więc przenoszę ją tutaj, aby uniknąć pytań, na które już odpowiedziałem.

Kompilator optymalizujący może zauważyć, że ten kod nie robi nic i może zoptymalizować to wszystko. Zadaniem optymalizatora jest robienie takich rzeczy, a walka z optymalizatorem to głupota.

Polecam skompilowanie tego kodu z wyłączoną optymalizacją, ponieważ nie ma dobrego sposobu, aby oszukać każdego optymalizatora obecnie używanego lub który będzie używany w przyszłości.

Każdy kto włączy optymalizator a potem narzeka na walkę z nim powinien być publicznie wyśmiewanie.

Gdyby zależało mi na nanosekundowej precyzji nie używałbym std::clock(). Gdybym chciał opublikować wyniki jako pracę doktorską, zrobiłbym o tym większy interes i prawdopodobnie porównałbym GCC, Tendra / Ten15, LLVM, Watcom, Borland, Visual C++, Digital Mars, ICC i inne Kompilatory. Jak to jest, alokacja sterty trwa setki razy dłużej niż alokacja stosu, i nie widzę nic użytecznego w badaniu tego pytania dalej.

Optymalizator ma misja pozbycia się kodu, który testuję. Nie widzę powodu, aby powiedzieć optymalizator uruchomić, a następnie spróbować oszukać optymalizator nie faktycznie optymalizacji. Ale gdybym widział wartość w robieniu tego, zrobiłbym jedną lub więcej z następujących rzeczy:

  1. Jeśli tylko kiedykolwiek odczytam z elementu danych, optymalizator może wykonywać stałe składanie i usuwać pętlę; jeśli tylko kiedykolwiek napiszę do elementu danych, optymalizator może pomiń wszystkie oprócz ostatniej iteracji pętli. Dodatkowo, pytanie nie brzmiało " alokacja stosu i dostęp do danych a alokacja sterty i dostęp do danych."

  2. Declare e volatile, ale {[8] } jest często kompilowany niepoprawnie (PDF).

  3. Weź adres e wewnątrz pętli (i może przypisz go do zmiennej zadeklarowanej extern i zdefiniowanej w innym pliku). Ale nawet w tym przypadku kompilator może zauważyć, że-na stosie przynajmniej -- e będą zawsze przydzielane pod tym samym adresem pamięci, a następnie będą składane jak w (1) powyżej. Dostaję wszystkie iteracje pętli, ale obiekt nigdy nie jest faktycznie alokowany.

Poza oczywistym, ten test jest wadliwy, ponieważ mierzy zarówno alokację, jak i dealokację, a pierwotne pytanie nie pytało o dealokację. Oczywiście zmienne przydzielone na stosie są automatycznie dealokowane na końcu ich zakresu, więc nie wywołanie delete would (1) przekrzywiamy liczby (dealokacja stosu jest zawarta w liczbach dotyczących alokacji stosu, więc jest to sprawiedliwe, aby zmierzyć dealokację stosu) i (2) spowodujemy dość zły wyciek pamięci, chyba że zachowamy odniesienie do nowego wskaźnika i wywołamy delete po mierzeniu czasu.

Na moim komputerze, używając g++ 3.4.4 w systemie Windows, dostaję "0 wskazów zegara" zarówno dla alokacji stosu, jak i sterty dla wszystkiego mniej niż 100000 alokacji, a nawet wtedy dostaję "0 wskazów zegara" dla alokacji stosu i " 15 ticks clock " dla alokacji sterty. Kiedy mierzę 10,000,000 alokacji, alokacja stosu zajmuje 31 wskazów zegara, a alokacja sterty zajmuje 1562 wskazów zegara.


Tak, kompilator optymalizujący może uniknąć tworzenia pustych obiektów. Jeśli dobrze rozumiem, może nawet ominąć całą pierwszą pętlę. Kiedy podniosłem iteracje do 10,000,000 alokacja stosu zajęła 31 kleszczy zegara, a alokacja sterty zajęła 1562 kleszczy zegara. Myślę, że można to powiedzieć bez mówienia g++ do zoptymalizuj plik wykonywalny, g++ nie ominął konstruktorów.


W latach, od kiedy to napisałem, preferowanym sposobem na przepełnienie stosu było publikowanie wydajności ze zoptymalizowanych kompilacji. Ogólnie rzecz biorąc, uważam, że jest to poprawne. Jednak nadal uważam, że to głupie poprosić kompilatora, aby zoptymalizować kod, gdy w rzeczywistości nie chcesz, aby ten kod zoptymalizowany. Wydaje mi się, że jest bardzo podobny do płacenia za parkowanie parkingowego, ale odmawia przekazania kluczy. W tym konkretnym przypadku nie chcę, aby optymalizator działał.

Użycie nieco zmodyfikowanej wersji benchmarka (aby rozwiązać poprawny punkt, w którym oryginalny program nie przydzielał czegoś na stosie za każdym razem przez pętlę) i kompilowanie bez optymalizacji, ale linkowanie do bibliotek wydań (aby rozwiązać poprawny punkt, w którym nie chcemy uwzględniać żadnego spowolnienia spowodowanego połączeniem z bibliotekami debugowania): {]}

#include <cstdio>
#include <chrono>

namespace {
    void on_stack()
    {
        int i;
    }

    void on_heap()
    {
        int* i = new int;
        delete i;
    }
}

int main()
{
    auto begin = std::chrono::system_clock::now();
    for (int i = 0; i < 1000000000; ++i)
        on_stack();
    auto end = std::chrono::system_clock::now();

    std::printf("on_stack took %f seconds\n", std::chrono::duration<double>(end - begin).count());

    begin = std::chrono::system_clock::now();
    for (int i = 0; i < 1000000000; ++i)
        on_heap();
    end = std::chrono::system_clock::now();

    std::printf("on_heap took %f seconds\n", std::chrono::duration<double>(end - begin).count());
    return 0;
}

Wyświetlenia:

on_stack took 2.070003 seconds
on_heap took 57.980081 seconds

W moim systemie po skompilowaniu z wierszem poleceń cl foo.cc /Od /MT /EHsc.

Możesz nie zgodzić się z moim podejściem do uzyskania nieoptymalizowanej kompilacji. W porządku: nie krępuj się modyfikować benchmarka tak bardzo, jak chcesz. Kiedy włączam optymalizację, dostaję:

on_stack took 0.000000 seconds
on_heap took 51.608723 seconds

Nie dlatego, że alokacja stosu jest tak naprawdę natychmiastowa, ale dlatego, że każdy pół przyzwoity kompilator może zauważyć, że on_stack nie robi nic użytecznego i może być zoptymalizowany. GCC na moim laptopie z Linuksem również zauważa, że on_heap nie robi nic użytecznego i optymalizuje go jako cóż:

on_stack took 0.000003 seconds
on_heap took 0.000002 seconds
 109
Author: Max Lybbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-14 13:37:56

Ciekawostką, którą dowiedziałem się o alokacji stosu kontra sterty na procesorze Xenon Xbox 360, co może mieć również zastosowanie do innych systemów wielordzeniowych, jest to, że alokacja na stercie powoduje wprowadzenie sekcji krytycznej, aby zatrzymać wszystkie inne rdzenie, tak aby alloc nie powodował konfliktu. Tak więc, w ciasnej pętli, alokacja stosu była drogą do zrobienia dla tablic o stałych rozmiarach, ponieważ zapobiegała straganom.

Może to być kolejne przyspieszenie do rozważenia, jeśli kodujesz dla multicore/multiproc, w tym twoim alokacja stosu będzie widoczna tylko przez rdzeń z uruchomioną funkcją scoped i nie wpłynie to na żadne inne rdzenie / Procesory.

 27
Author: Furious Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-02 01:55:50

Możesz napisać specjalny alokator stosów dla określonych rozmiarów obiektów, który jest bardzo wydajny. Jednak alokator stosu ogólnego nie jest szczególnie wydajny.

Zgadzam się również z Torbjörnem Gyllebringiem co do oczekiwanej żywotności obiektów. Słuszna Uwaga!

 17
Author: Chris Jester-Young,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 06:08:22

Nie sądzę, aby alokacja stosu i alokacja sterty były ogólnie wymienne. Mam również nadzieję, że wydajność obu z nich jest wystarczająca do ogólnego użytku.

Zdecydowanie polecam dla małych przedmiotów, które są bardziej odpowiednie do zakresu przydziału. W przypadku dużych przedmiotów sterta jest prawdopodobnie konieczna.

W 32-bitowych systemach operacyjnych, które mają wiele wątków, stos jest często raczej ograniczony (choć zazwyczaj do co najmniej kilku mb), ponieważ przestrzeń adresowa musi być rzeźbione i prędzej czy później jeden stos wątków trafi na inny. W systemach z pojedynczym wątkiem (Linux glibc single threaded anyway) ograniczenie jest znacznie mniejsze, ponieważ stos może po prostu rosnąć i rosnąć.

W 64-bitowych systemach operacyjnych jest wystarczająco dużo przestrzeni adresowej, aby stosy wątków były dość duże.

 6
Author: MarkR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 06:12:26

Zazwyczaj alokacja stosu polega na odejmowaniu od rejestru wskaźników stosu. To jest o wiele szybsze niż szukanie sterty.

Czasami alokacja stosu wymaga dodania strony(stron) pamięci wirtualnej. Dodanie nowej strony z zerowaną pamięcią nie wymaga odczytu strony z dysku, więc zwykle będzie to nadal dużo szybsze niż przeszukiwanie sterty(zwłaszcza jeśli część sterty też była stronicowana). W rzadkiej sytuacji, i można skonstruować taki przykład, wystarczająco dużo miejsca tak się składa, że jest dostępna w części sterty, która jest już w pamięci RAM, ale przydzielanie nowej strony do stosu musi poczekać, aż inna strona zostanie zapisana na dysk. W tej rzadkiej sytuacji sterta jest szybsza.

 6
Author: Windows programmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 06:18:26

Oprócz przewagi wydajności rzędu wielkości nad alokacją sterty, alokacja stosu jest preferowana w przypadku długotrwałych aplikacji serwerowych. Nawet najlepiej zarządzane sterty są tak rozdrobnione, że wydajność aplikacji spada.

 6
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-26 17:36:00

Stos ma ograniczoną pojemność, podczas gdy stos nie jest. Typowy stos dla procesu lub wątku wynosi około 8K. nie można zmienić rozmiaru po jego przydzieleniu.

Zmienna stosu postępuje zgodnie z regułami zakresów, podczas gdy zmienna stosu nie. jeśli wskaźnik instrukcji wykracza poza funkcję, wszystkie nowe zmienne powiązane z funkcją znikają.

Najważniejsze, że nie można przewidzieć całego łańcucha wywołania funkcji z góry. Więc tylko 200 bajtów alokacji z twojej strony może podnieść przepełnienie stosu. Jest to szczególnie ważne, jeśli piszesz bibliotekę, a nie aplikację.

 4
Author: yogman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 16:57:39

Myślę, że żywotność jest kluczowa i czy rzecz przydzielana musi być skonstruowana w sposób złożony. Na przykład w modelowaniu opartym na transakcjach zwykle trzeba wypełnić i przekazać strukturę transakcji z kilkoma polami do funkcji operacyjnych. Spójrz na osci SystemC TLM-2.0 standard dla przykładu.

Przypisanie ich do stosu blisko wywołania operacji powoduje ogromne koszty, ponieważ konstrukcja jest kosztowna. The good way there jest przydzielanie na stercie i ponowne wykorzystanie obiektów transakcji poprzez łączenie lub prostą zasadę, taką jak "ten moduł potrzebuje tylko jednego obiektu transakcji kiedykolwiek".

Jest to wielokrotnie szybsze niż przydzielanie obiektu do każdego wywołania operacji.

Powodem jest po prostu to, że obiekt ma kosztowną konstrukcję i dość długą żywotność.

Powiedziałbym: spróbuj obu i zobacz, co działa najlepiej w Twoim przypadku, ponieważ może to naprawdę zależeć od zachowania Twojego kodu.

 3
Author: jakobengblom2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 06:43:14

Prawdopodobnie największym problemem alokacji sterty w porównaniu do alokacji stosu jest to, że alokacja sterty w ogólnym przypadku jest operacją nieograniczoną, dlatego nie można jej używać tam, gdzie problemem jest czas.

W przypadku innych aplikacji, w których czas nie jest problemem, może to nie mieć znaczenia, ale jeśli dużo przydzielisz, wpłynie to na szybkość wykonania. Zawsze staraj się używać stosu do krótkotrwałej i często przydzielanej pamięci (na przykład w pętlach), a jak najdłużej - do stosu alokacja podczas uruchamiania aplikacji.

 3
Author: larsivi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 08:34:12

To nie alokacja stosu jsut jest szybsza. Dużo wygrywasz również na używaniu zmiennych stosu. Mają lepszą lokalizację odniesienia. I wreszcie, dealokacja jest o wiele tańsza.

 3
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-03 15:35:41

Alokacja stosu będzie prawie zawsze tak szybka lub szybsza niż alokacja sterty, chociaż z pewnością jest możliwe, aby alokator stosu po prostu używał techniki alokacji opartej na stosie.

Istnieją jednak większe problemy, jeśli chodzi o ogólną wydajność alokacji opartej na stosie i stercie (lub w nieco lepszym znaczeniu, alokacji lokalnej i zewnętrznej). Zazwyczaj alokacja sterty (zewnętrzna) jest powolna, ponieważ zajmuje się wieloma różnymi rodzajami alokacji i alokacji wzory. Zmniejszenie zakresu alokatora, którego używasz (uczynienie go lokalnym algorytmem / kodem) będzie miało tendencję do zwiększania wydajności bez większych zmian. Dodanie lepszej struktury do wzorców alokacji, na przykład wymuszanie kolejności LIFO na parach alokacji i dealokacji może również poprawić wydajność alokatora, używając alokatora w prostszy i bardziej zorganizowany sposób. Możesz też użyć lub napisać alokator dostrojony do określonego wzorca alokacji; większość programów przydziel kilka dyskretnych rozmiarów często, więc kupa, która jest oparta na buforze lookaside kilku stałych (najlepiej znanych) rozmiarów, będzie działać bardzo dobrze. Z tego właśnie powodu System Windows używa swojej niskiej fragmentacji.

Z drugiej strony, alokacja oparta na stosie na 32-bitowym zakresie pamięci jest również obarczona niebezpieczeństwem, jeśli masz zbyt wiele wątków. Stosy potrzebują przylegającego zakresu pamięci, więc im więcej wątków masz, tym więcej wirtualnej przestrzeni adresowej będziesz potrzebować, aby działały bez przepełnienie stosu. Nie będzie to problemem (na razie) z 64-bitowym, ale z pewnością może siać spustoszenie w długich programach z dużą ilością wątków. Brak wirtualnej przestrzeni adresowej z powodu fragmentacji jest zawsze uciążliwy.

 3
Author: MSN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-10 16:27:39

Alokacja stosu to kilka instrukcji, podczas gdy najszybszy znany mi alokator stosów rtos (TLSF) używa średnio na zamówienie 150 instrukcji. Również alokacje stosów nie wymagają blokady, ponieważ używają lokalnego magazynu wątku, co jest kolejną ogromną wygraną wydajności. Tak więc alokacje stosów mogą być o 2-3 rzędy wielkości szybsze w zależności od tego, jak silnie wielowątkowe jest twoje środowisko.

Ogólnie przydział sterty jest ostatnią deską ratunku, jeśli zależy ci na wydajności. Realny pomiędzy opcją może być alokator puli stałej, który jest również tylko kilkoma instrukcjami i ma bardzo mały narzut na alokację, więc jest świetny dla małych obiektów o stałym rozmiarze. Z drugiej strony działa tylko z obiektami o stałym rozmiarze, nie jest z natury bezpieczny dla wątku i ma problemy z fragmentacją bloków.

 3
Author: Andrei Pokrovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-17 20:30:17

Jest ogólna uwaga na temat takich optymalizacji.

Uzyskana optymalizacja jest proporcjonalna do czasu, w którym licznik programu faktycznie znajduje się w tym kodzie.

Jeśli spróbujesz licznika programu, dowiesz się, gdzie spędza on swój czas, a to zwykle jest w niewielkiej części kodu, a często w procedurach bibliotecznych, nad którymi nie masz kontroli.

Tylko jeśli znajdziesz go spędzającego dużo czasu w stercie-alokacji obiektów będzie zauważalnie szybszy stos-przydzielić je.

 2
Author: Mike Dunlavey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-27 20:41:51

Przydzielanie stosu jest znacznie szybsze.

 2
Author: Master Yoda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-17 20:56:09

Jak mówili inni, przydzielanie stosów jest na ogół znacznie szybsze.

Jednakże, jeśli kopiowanie obiektów jest kosztowne, przydzielanie na stosie może prowadzić do ogromnego uderzenia wydajności później, gdy używasz obiektów, jeśli nie jesteś ostrożny.

Na przykład, jeśli przydzielisz coś na stosie, a następnie umieścisz to w kontenerze, lepiej byłoby przydzielić coś na stosie i zapisać wskaźnik w kontenerze (np. używając std::shared_ptr). To samo jest prawdą, jeśli jesteś przekazywanie lub zwracanie obiektów według wartości i inne podobne scenariusze.

Chodzi o to, że chociaż alokacja stosu jest zwykle lepsza niż alokacja stosu w wielu przypadkach, czasami jeśli idziesz na swoją drogę do alokacji stosu, gdy nie pasuje to najlepiej do modelu obliczeń, może to spowodować więcej problemów niż rozwiązuje.

 2
Author: wjl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-05 15:46:32
class Foo {
public:
    Foo(int a) {

    }
}
int func() {
    int a1, a2;
    std::cin >> a1;
    std::cin >> a2;

    Foo f1(a1);
    __asm push a1;
    __asm lea ecx, [this];
    __asm call Foo::Foo(int);

    Foo* f2 = new Foo(a2);
    __asm push sizeof(Foo);
    __asm call operator new;//there's a lot instruction here(depends on system)
    __asm push a2;
    __asm call Foo::Foo(int);

    delete f2;
}

Byłoby tak w asm. Gdy znajdujesz się w func, f1 i wskaźnik f2 zostały przydzielone na stos (zautomatyzowane przechowywanie). A tak przy okazji, Foo f1(a1) nie ma efektów instrukcji na wskaźniku stosu (esp), została przydzielona, Jeśli func chce dostać członka f1, to jej instrukcja jest mniej więcej taka: lea ecx [ebp+f1], call Foo::SomeFunc(). Inna sprawa, że przydzielanie stosu może sprawić, że ktoś pomyśli, że pamięć jest czymś w rodzaju FIFO, FIFO właśnie się stało, gdy wchodzi się do jakiejś funkcji, jeśli jest się w funkcja i przydzielanie czegoś w rodzaju int i = 0, nie doszło do wypychania.

 2
Author: bitnick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-05 03:13:10

Wspomniano wcześniej, że alokacja stosu polega na przesuwaniu wskaźnika stosu, czyli pojedynczej instrukcji na większości architektur. Porównaj to z tym, co ogólnie dzieje się w przypadku alokacji sterty.

System operacyjny utrzymuje porcje wolnej pamięci jako powiązaną listę z danymi ładunku składającą się ze wskaźnika do adresu początkowego wolnej porcji i jej rozmiaru. Aby przydzielić X bajtów pamięci, lista łączy jest przesuwana i każda nuta jest odwiedzana w kolejności, sprawdzając, czy jej rozmiar wynosi co najmniej X. Gdy znaleziona jest część O rozmiarze P > = X, P jest dzielona na dwie części o rozmiarach X I P-X. lista połączona jest aktualizowana i zwracany jest wskaźnik do pierwszej części.

Jak widać, przydział sterty zależy od czynników, takich jak ilość pamięci, o którą prosisz, jak fragmentaryczna jest pamięć i tak dalej.

 1
Author: Nikhil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-02 00:46:06

Ogólnie rzecz biorąc, alokacja stosu jest szybsza niż alokacja stosu, o czym wspomina prawie każda odpowiedź powyżej. Push lub pop stosu to O (1), podczas gdy alokacja lub uwolnienie ze stosu może wymagać przejścia poprzednich alokacji. Jednak zazwyczaj nie powinno się przydzielać ciasnych pętli o dużej wydajności, więc wybór zwykle sprowadza się do innych czynników.

Dobrze byłoby to rozróżnić: możesz użyć "alokatora stosu"na stercie. Ściśle mówiąc, biorę stack przydział oznacza Rzeczywistą metodę przydziału,a nie miejsce przydziału. Jeśli przydzielasz wiele rzeczy na rzeczywisty stos programów, może to być złe z różnych powodów. Z drugiej strony, użycie metody stosu do alokacji na stercie, jeśli to możliwe, jest najlepszym wyborem, jaki możesz zrobić dla metody alokacji.

Skoro wspomniałeś o Metrowerks i PPC, zgaduję, że masz na myśli Wii. W tym przypadku pamięć jest na poziomie premium i przy użyciu metody alokacji stosu w miarę możliwości gwarantuje, że nie marnujesz pamięci na fragmenty. Oczywiście, robienie tego wymaga o wiele więcej uwagi niż" normalne " metody alokacji sterty. Mądrze jest Oceniać kompromis dla każdej sytuacji.

 1
Author: Dan Olson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-02 01:36:43

Uwaga, że przy wyborze stosu zamiast alokacji stosu zazwyczaj nie chodzi o szybkość i wydajność. Stos działa jak stos, co oznacza, że dobrze nadaje się do pchania bloków i popping je ponownie, ostatni w, pierwszy na zewnątrz. Wykonywanie procedur jest również podobne do stosu, ostatnia wprowadzona procedura jest pierwszą zakończoną. W większości języków programowania, wszystkie zmienne potrzebne w procedurze będą widoczne tylko podczas jej wykonywania, dlatego są one popychane na wprowadzenie procedury i wyskoczył ze stosu po wyjściu lub powrocie.

Teraz przykład, w którym stos nie może być użyty:

Proc P
{
  pointer x;
  Proc S
  {
    pointer y;
    y = allocate_some_data();
    x = y;
  }
}

Jeśli przydzielisz część pamięci w procedurze S i umieścisz ją na stosie, a następnie zakończysz S, przydzielone dane zostaną usunięte ze stosu. Ale zmienna x W P również wskazywała na te dane, więc x wskazuje teraz na jakieś miejsce pod wskaźnikiem stosu (Załóżmy, że stos rośnie w dół) z nieznaną zawartością. Zawartość może nadal tam być, jeśli stos wskaźnik jest po prostu przesuwany w górę bez czyszczenia danych pod nim, ale jeśli zaczniesz przydzielać nowe dane na stosie, wskaźnik x może faktycznie wskazywać na te nowe dane zamiast.

 1
Author: Kent Munthe Caspersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 08:24:38

Nigdy nie rób przedwczesnego założenia, ponieważ inny kod aplikacji i użycie może mieć wpływ na twoją funkcję. Więc patrząc na funkcję jest izolacja jest bezużyteczny.

Jeśli poważnie myślisz o aplikacji, to VTune go lub użyj podobnego narzędzia do profilowania i spójrz na hotspoty.

Ketan

 0
Author: Ketan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-04 17:21:37

Chciałbym powiedzieć, że rzeczywiście kod generowany przez GCC (pamiętam również VS) nie ma narzutu do alokacji stosu .

Powiedz dla następującej funkcji:

  int f(int i)
  {
      if (i > 0)
      {   
          int array[1000];
      }   
  }

Poniżej znajduje się wygenerowany kod:

  __Z1fi:
  Leh_func_begin1:
      pushq   %rbp
  Ltmp0:
      movq    %rsp, %rbp
  Ltmp1:
      subq    $**3880**, %rsp <--- here we have the array allocated, even the if doesn't excited.
  Ltmp2:
      movl    %edi, -4(%rbp)
      movl    -8(%rbp), %eax
      addq    $3880, %rsp
      popq    %rbp
      ret 
  Leh_func_end1:

Więc ile masz zmiennych lokalnych (nawet wewnątrz if lub switch), tylko 3880 zmieni się na inną wartość. O ile nie masz zmiennej lokalnej, ta instrukcja wystarczy wykonać. Przeznaczyć zmienną lokalną nie ma narzutu.

 -1
Author: ZijingWu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-24 07:04:22