Wo ist der Stack



  • Es ist legal für new malloc zu verwenden um den Speicher anzufordern - das sollte die Unterschiede doch klären, oder? 😉

    Nämlich: es gibt keinen. Bei new nennt es sich halt Freestore und bei malloc Heap.



  • Es ist legal für new malloc zu verwenden um den Speicher anzufordern

    Daraus ergibt sich der Freestore darf im Heap sein. Das bedeutet aber nicht, das die beiden gleichbedeutend sind. Vielleicht kann man den Freestore besonders aufbauen, um schnellere Allokationen von kleinen Objekten zu erlauben, statt von großen oder so.



  • Der Unterschied ist, dass free store ein fester Begriff des C++ Standards und Heap nicht.
    Im C++ Standard werden im Kapitel 12.5 Free store die Eigenschaften von new/delete beschrieben und bestimmte Bedingungen festgelegt.
    Gleichzeitig sagt der Standard, dass:
    a) malloc, calloc, realloc, free nicht über new/delete implementiert werden dürfen,
    b) zwischen new/delete und *alloc/free keinerlei Beziehung bestehen muss.

    Wir haben also einen festen Begriff "free store" auf der einen Seite und Memory-Management-Funktionen malloc, calloc, realloc, free auf der anderen Seite.
    Der C-Standard vergibt keinen festen Namen für den Bereich auf dem malloc und Co arbeiten. Da dieser Bereich aber praktisch immer als Heap implementiert ist, heißt er Heap. Der Name ist aber eigentlich auch irrelevant.

    Wichtig ist die Tatsache, dass new/delete und malloc/free auf konzeptionell unterschiedlichen Speicherbereichen arbeiten, dass der von new/delete "free store" heißt und dass beide Bereiche nicht austauschbar sind.

    Deshalb ist es an der Grenze zwischen C und C++ wichtig zwischen free store und Heap zu unterscheiden. Betrachtet man hingegen sowieso nur new/delete ist diese Unterscheidung imo überflüssig. Auch der free store ist praktisch immer als Heap implementiert und von daher spricht in diesem Fall nichts gegen eine Aussage wie "new allokiert Speicher auf dem Heap".

    PS: Aber bis auf den letzten Teil steht das letztlich doch alles auch in Sutters "Exceptional C++" 🙄



  • @Stackpointer

    Ich habe nur ein Verständnisproblem noch.
    Wenn eine Variable auf dem Stack abgelegt wird und anschließend noch eine dann komme ich ja immer nur an die oberste dran. Wenn ich aber an die darunter liegende dran kommen will, wie mach ich das denn? Wer entscheidet das?

    Aehm das ding heisst ned Stack, weil die Variablen im Code wie ein STack behandelt werden, sondern die Funktionsbloecke ... Also der Speicher in Abhaengigkeit vom Ablauf erweitert und wieder dezimiert wird.
    Das Tut der compiler und das BS fuer dich ...

    Musst dir das so vorstellen :

    int f(int i)
    {
        // das ist mein 2ter Block ....     
        int x = 45; 
        return x;
    }
    
    int main()
    {
        // Main ist mein unterster block .... 
        int i = 4;
        i = f(i);
    }
    

    dein compiler compiliert das (hoffe ich mal) und legt binaercode dafuer an.
    Wird der binaercode vom Loader des BS geladen (in den Hauptspeicher, klar) ein prozess erzeugt, und bevor der Prozess mit dem einsprungpunkt(int main() ) gestartet wird , wird fuer das Programm vom BS noch mehrere Arten von Speicher reserviert. Der Grundlegenste ist der Stack .....

    Nun hat der Compiler deinen Code in binaere anweisungen gewandelt, und das erste was dein prog macht, befor es ueberhaupt anfaengt den code abzuarbeiten, ist den speicher fuer die Variablen in main zu reserverieren, und zwar auf den Stack ....

    In den oben genannten teil beispielsweise 4 Byte (und noch ne ganze menge mehr fuer andere sachen und variablen die du ned so siehst ) .....
    nun faengt der Prozess an zu arbeiten, und kommt zu dem funktionsaufruf f !

    fuer nen funktionsaufruf wird speicher fuer die argumente, der rueckgabewert und auch fuer die ruecksprungadresse benoetigt, diese werden an der stelle aufn Stack angelegt, und befuellt. .... bevor nun der prozess anfaengt f abzuarbeiten, wird noch der Speicher fuer die in f1 verwendeten variablen angelegt, das wird natuerlich auch auf den stack gemacht

    f wird abgearbeitet, wenn fertig, dann wird der speicher von den variablen fuer f wieder entfernt,
    danach die rueckgabewerte in main ubernommen und dancach auch der speicher fuer rueckabewert, argumente und der rueckabeadresse freigegeben ...

    danach gehts in main weiter, und wenn main fertig ist, werden die speicherberieche fuer dein main wieder vom stack freigegeben ...

    Dein compiler macht dafuer die meiste arbeit und baut den binaercode so, das es funktioniert ....
    er allociert den speicher natuerlich ned einzeln, sondern schoen blockweise .... und damit das funzt, musst der compiler natuerlich wissen, wieviel speicher er fuer deine Funktion / Programm anlegen muss. Deshalb gehen z.B. keine Arrays mit dynamischer groesse auf dem "Stack"

    Den Namen hat der Stack von seiner Arbeitsweise bekommen .... weil er dieser speicher ein "Stapel" behandlet wird, eintritt in main ... , erhoehe den Stackzeihger um das was mein braucht, und der speichermanager von mein bekommt die alte stackadresse und heut seine variablen dahin ....
    eintritt in f ... erhoehe den Stackzeiger um das was fuer f gebraucht wird, f bekommt den zeiger auf die alte adresse und legt seine variablen dahin ...
    Austritt aus f, der Stackzeiger wird um das was f gebraucht hat zurueckgesetzt ...

    etc ....

    Naja, so funzt das ansatzweise ... grob vereinfacht dargestellt ....

    WIssen muss man:
    Der STack ist dein grundlegender Speicher ...
    Der stack ist schnell, weil er keinen Speichermanager braucht ... sondern das zeugs per binaercode blockweise angwfordert wird, und in reihenfolge wieder freigegeben wenn nimmer gebraucht. Speicherluecken koennen theorethisch ned auftreten.
    Dein verbrauch an "Stackspeicher" muss demnach zur compilezeit bekannt sein"
    es gibt grenzen vom Stack die vom BS vorgegeben werden ....

    Ciao ...



  • Ich habe noch eine Frage zu den static Variablen und den globalen Variablen, wo werden diese gespeichert?

    Und der Code des Programms?

    Mein Prof. zählte diese Speicherbereiche auf: Betriebssystem, Stack, Heap, Codebereich, Datenbereich.

    Was ist mit dem Datenbereich, sind dort auch Variablen und außerdem hat er gesagt das die static Variablen im Codebereich liegen.

    Das ist jedenfalls das, was ich aus seinem Durcheinander erkennen konnte. 😞

    Ich danke für Infor mationen.

    mfg Mr.Schottky 😉



  • Mr.Schottky schrieb:

    Was ist mit dem Datenbereich, sind dort auch Variablen

    Logisch.

    Mr.Schottky schrieb:

    und außerdem hat er gesagt das die static Variablen im Codebereich liegen.

    Vermutlich eher nicht. Früher, zu DOS Zeiten, hat man mal sowas gemacht. Heutzutage gibt es dafür keinen Grund mehr.



  • Welche Variablen liegen dann im Datenbereich?

    Lokale?



  • Statische und globale.



  • Können globale Variablen im Daten- und im Codebereich liegen?

    Tut mir leid das ich euch Löcher in den Bauch frage!
    😃



  • Lies dir Optimizer's Beitrag nochmal durch, dann ist eine Hälfte schon beantwortet. Globale Variablen können afaik auch im Codesegment liegen. Funktionen sind ja auch sowas wie globale Variablen mit festem Inhalt. 😃 Allerdings sind solche Sachen wohl plattformabhängig.



  • HumeSikkins schrieb:

    Gleichzeitig sagt der Standard, dass:
    a) malloc, calloc, realloc, free nicht über new/delete implementiert werden dürfen,
    b) zwischen new/delete und *alloc/free keinerlei Beziehung bestehen muss.

    sehr vernümpftig.
    damit hat er faktisch erlaubt, daß man new über malloc implemetieren kann.

    für die leutchen, die sich um performance gedanken machen, gipt's noch einen untersched. der heap (malloc/free) ist für typische c-anwenungen optimiert und der freispeicher (new/delete) ist für typische c++-anwendungen optimiert. und das heißt konkret, daß malloc objekte beliebiger größen einigermaßen gut besorgt und daß new mehrkosten für große objekte zahlt, um kleinere objekte schnell zu besorgen. immerhinque ist while(file>>age>>sex>>location) bunnies.push_back(new Person(age,sex,location)); völlig normaler stil in c++. da muß new für viele kleine objekte rulen.



  • Gut, ich fasse zusammen:

    Stack: lokale Variablen
    Heap: allokierte Variablen
    Datenbereich: static und globale Variablen
    Codesegment: glabale Variablen



  • volkard schrieb:

    der freispeicher (new/delete) ist für typische c++-anwendungen optimiert. und das heißt konkret, daß malloc objekte beliebiger größen einigermaßen gut besorgt und daß new mehrkosten für große objekte zahlt, um kleinere objekte schnell zu besorgen. immerhinque ist while(file>>age>>sex>>location) bunnies.push_back(new Person(age,sex,location)); völlig normaler stil in c++. da muß new für viele kleine objekte rulen.

    Hmm, Alexandrescu schreibt das genaue Gegenteil (Modern C++ Design) und stellt deshalb ja seinen SmallObjAllocator vor. Ist das mittlerweile anders? Meine Ausgabe ist von 2003...



  • Cocaine schrieb:

    volkard schrieb:

    der freispeicher (new/delete) ist für typische c++-anwendungen optimiert. und das heißt konkret, daß malloc objekte beliebiger größen einigermaßen gut besorgt und daß new mehrkosten für große objekte zahlt, um kleinere objekte schnell zu besorgen. immerhinque ist while(file>>age>>sex>>location) bunnies.push_back(new Person(age,sex,location)); völlig normaler stil in c++. da muß new für viele kleine objekte rulen.

    Hmm, Alexandrescu schreibt das genaue Gegenteil (Modern C++ Design) und stellt deshalb ja seinen SmallObjAllocator vor. Ist das mittlerweile anders? Meine Ausgabe ist von 2003...

    Ich weiß nicht gegen was Alexandrescu seinen Allokator getestet hat, aber gegen die Standard-New-Implementation des VC 6.0 hatte das Ding nie auch nur den Hauch einer Chance. Das Kapitel in Modern C++ Design bespricht ein paar wichtige Dinge und die Theorie ist sicher richtig, die Implementation des Allokators kann man aber ohne weiteres in die Kategorie "nur zum Lernen geeignet" einsortieren. Eine praktische Relevanz hat das Ding nicht.



  • HumeSikkins schrieb:

    Ich weiß nicht gegen was Alexandrescu seinen Allokator getestet hat, aber gegen die Standard-New-Implementation des VC 6.0 hatte das Ding nie auch nur den Hauch einer Chance.

    Ja, ich war davon auch sehr enttäuscht. IMHO ist es auch nicht so gut möglich nur mit C++ Boardmitteln einen verdammt schnellen Allokator zu schreiben.

    Volkards SmallAlloc ist dagegen ein verdammt geiles und schnelles Ding.



  • Mr.Schottky schrieb:

    Codesegment: glabale Variablen

    Lass das weg. Wie der Name schon sagt, befindet sich hier der ausführbare Code. Ich kenne auch keinen C++ Compiler, der hier vom User erstellte Variablen ablegt. Willst du sowas machen, musst du dich wohl in die Tiefen der Assembler Programmierung stürzen.



  • Shade Of Mine schrieb:

    Volkards SmallAlloc ist dagegen ein verdammt geiles und schnelles Ding.

    Kann man sich den irgendwo mal anschaun?



  • Cocaine schrieb:

    volkard schrieb:

    der freispeicher (new/delete) ist für typische c++-anwendungen optimiert. und das heißt konkret, daß malloc objekte beliebiger größen einigermaßen gut besorgt und daß new mehrkosten für große objekte zahlt, um kleinere objekte schnell zu besorgen. immerhinque ist while(file>>age>>sex>>location) bunnies.push_back(new Person(age,sex,location)); völlig normaler stil in c++. da muß new für viele kleine objekte rulen.

    Hmm, Alexandrescu schreibt das genaue Gegenteil (Modern C++ Design) und stellt deshalb ja seinen SmallObjAllocator vor. Ist das mittlerweile anders? Meine Ausgabe ist von 2003...

    alexandrescu schreibt, warum new praktisch nen small object allocator eingebaut haben sollte und warum malloc das nicht so braucht. außerdem sagt er, wie man sich einen selber machen kann, wenn man keinen im new drin hat. ich postuliere, daß nun endlich einer drin ist, weil die compilerbauer auch sein buch gelesen haben. oder sonstwie halt dafür sogen, daß new für c++ gut ist und malloc für c gut ist.


Anmelden zum Antworten