stack/heap



  • Hallo,

    Wichtig? Komm erstmal in die Datenbankerstellung 🙄.

    MFG winexec*



  • Der Stack funktioniert eben nach einfachem Stapel-Prinzip. Wenn man Daten speichern will, dann legt man es einfach oben drauf. Wenn die Daten ungültig werden, hebt man sie einfach von oben ab. Der Stack ist nicht sonderlich groß (die größe ist vom Betriebssystem und diversen Einstellungen abhängig)

    Der Heap dagegen arbeitet mit komplizierten Algorithmen und Tabellen, um die Speicheranforderungen sinnvoll zu verteilen. Dafür kann man aber Speicher jederzeit freigeben. Der Heap ist für große und langlebige Daten gedacht, während der Stack für lokale Variablen und ähnliches genutzt wird (weil hier das drauflegen/abheben am leichtesten funktioniert).

    Normale Variablen werden auf dem Stack angelegt. Mit new bzw. new[] kannst du Speicher auf dem Heap anfordern (den du aber mittels delete bzw. delete[] manuell freigeben musst!). (In C++ lohnt sich aber für die Speicherverwaltung Smart-Pointer einzusetzen.)

    void foo() {
      int a = 0; // variable auf dem Stack
    } // hier wird die Variable automatisch "zerstört"
    


  • stapelprinzip sagt mir noch was LIFO last in, first out.
    push ax
    push bx

    pop bx
    pop ax
    .......

    wie ist das eigendlich wenn man den speicher nicht wieder freigibt?
    bleibt der speicher weiterhin reserviert, auch wenn man das programm
    beendet? oder nur innerhalb der laufzeit des programms?



  • Moderne Betriebssysteme räumen sämtlichen, von deinem Programm verwendeten speicher auf. Es ist jedoch good practice, selbst aufzuräumen.

    Greetz, Swordfish



  • Das Problem mit der Speicherfreigabe besteht, bei langlaufender Software (wie zB Servern).

    Die meisten GUI und Serverprogramme dürften ja ungefähr so aussehen

    init();
    while(event()) {
      handle_event();
    }
    deinit();
    

    Wenn du nun nicht sauber deine Resourcen freigibst und bei handle_event zB jedes mal 100 byte Speicher nicht freigibt, kannst du dir ja ausrechnen wie viele events dein Programm verarbeiten kann, bis der Speicher vollgelaufen ist und irgend wann der Rechner lahm liegt.



  • ahh noch eine frage,

    also wenn ich ein object mit new erstelle, werden dann
    die ganzen variablen des objects auf den heap gepackt?

    zumindest würde ich mir das so vorstellen, da ich sonst kein
    sinn sähe ein object mit new zu erstellen.
    oder sehe ich da was falsch?

    fragen über fragen



  • also wenn ich das richtig verstanden habe, müsste alles
    so in der art aussehen?

    include <iostream>
    #include <cstring>
    
    #include "datenbank.h"
    
    void progstart();
    void optionen();
    using namespace std;
    
    void main(void)
    {
    	DatenBank* myBank = new DatenBank;
    	progstart();
    	optionen();
    	delete myBank;
    }
    
    void progstart()
    {
    	cout<<"*******************************************"<<endl;
    	cout<<"* Programm zur Erstellung einer Datenbank.*"<<endl;
    	cout<<"* vers. 1.0                               *"<<endl;
    	cout<<"*                                         *"<<endl;
    	cout<<"*******************************************"<<endl;
    	cout<<endl<<endl;
    }
    
    void optionen()
    {
    	int* auswahl = new int;
    	char* temp = new char;
    	cout<<"--------------------------"<<endl;
    	cout<<"1. Neues Projekt erstellen"<<endl;
    	cout<<"2. Altes Projekt laden    "<<endl;
    	cout<<"--------------------------"<<endl;
    	cin>>*auswahl;
    
    	switch(*auswahl)
    	{
    	case 1:
    		cout<<"Neues Projekt"<<endl;
    		cin>>*temp;
    		break;
    	case 2:
    		cout<<"Altes Projekt"<<endl;
    		cin>>*temp;
    		break;
    		delete auswahl;
    		delete temp;
    	}
    }
    


  • Nein, in deinem Fall hast du ja in optionen() eine Speicherlücke, wenn der Benutzer 1 wählt.

    Außerdem sollte dir bewusst sein, dass du mit

    char *temp=new char;
    

    exakt Speicher für ein char anlegst.

    Generell macht es aber in deinem Programm wenig Sinn Speicher auf dem Heap zu erzeugen. Besonders für einzelne Variablen vom Typ int oä. Außerdem ist void main falsch!



  • Dieser Thread wurde von Moderator/in kingruedi aus dem Forum Rund um die Programmierung in das Forum C++ verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • ok, also kleine variablen, die keinen grösseren sinn haben,
    wie variablen für switch/case oä, nicht mit new.
    nur welche wo grosse datenmengen wie zb nen int array 640*480
    wo ich nen ganzes bild unterbringen könnte.

    delete aus der option funktion, hab ich mal aus switch case rausgenommen.
    und hinter "}" gesetzt.

    optionen() speicherlücke, leuchtet mir noch nicht ganz ein.
    (*noch nen schluck kaffe nimmt und hofft, dass es hilft*)

    danke hab mir mal den link zu void main in die favs gepackt, hatte das nie
    verstanden,hatte es so aus nem buch gelernt, hab 2 grundlagenbücher, da steht auch immer void main.

    edit:

    aja und void main() hab ich natürlich geändert:)



  • adonis schrieb:

    void optionen()
    {
        int* auswahl = new int;
        char* temp = new char;
        cout<<"--------------------------"<<endl;
        cout<<"1. Neues Projekt erstellen"<<endl;
        cout<<"2. Altes Projekt laden    "<<endl;
        cout<<"--------------------------"<<endl;
        cin>>*auswahl;
    
        switch(*auswahl)
        {
        case 1:
            cout<<"Neues Projekt"<<endl;
            cin>>*temp;
            break;
        case 2:
            cout<<"Altes Projekt"<<endl;
            cin>>*temp;
            break;
            delete auswahl;
            delete temp;
        }
    }
    

    Variablen mit kurzer Lebensdauer werden i.d.R. auf dem Stack abgelegt. Du würdest doch nicht

    for( int *i = new int( 1 ); *i <= 10; ++(*i) )
        cout << *i << endl;
    delete i;
    

    schreiben, oder?

    Beachte, dass eine Reservierung von Speicher auf dem Heap im allgemeinen langsamer ist, als ein einfaches PUSH auf dem Stack.

    Greetz, Swordfish



  • ok, noch eine frage:)

    geh ich recht in der annahme dass für jedes programm ein stack
    angelegt wird?

    ich mein jedes programm hat variablen die auf den stack gelegt werden.
    bei einer bestimten anzahl von laufenden programmen, würde ein
    einzelner stack ja vollaufen.

    oder gibt es einen fest reservierten bereich von einer bestimmeten
    grösse, was der gesamt stack ist, wo jedes programm einen teil zugewiesen bekommt worin er arbeiten kann?



  • Jedes Programm (eigentlich jeder Thread) bekommt seinen eigenen Stack.

    Greetz, Swordfish



  • Gründe den Stack dem Heap vorzuziehen:

    1. Die Destruktion wird automatisch vorgenommen
    2. Automatischer Destruktoraufruf beim stack-unwinding von try-catch
    3. Es kann kein delete vergessen werden -> keine Speicherlöcher
    4. Es kann nicht fälschlicherweise delete statt delete[] nach "new char[]"
    verwendet werden, keine Speicherlöcher durch vergessene Klammern []
    (ohne [] löscht delete nur die erste Speicherstelle des char[]-Arrays)
    5. "string" hat im Gegensatz zu "new char[]" eine vollkommen dynamische Länge
    6. Stack-Variablen können vom Compiler optimaler genutzt werden (Addressierung mittels ebp)
    7. Heap-Management sollte man generell immer der STL überlassen

    mfg



  • ok, wenn ich das jetzt also richtig verstanden habe.
    der stack wird nur anders verwaltet, als der heap.
    der ganze ram könnte auch ein kompletter stack sein, wenn man ihn
    so definiert.

    was wo als stack definiert wird regelt das betriebssystem.
    für jedes programm wir ein bereich im ram als stack definiert.

    wie ich stack und heap nutze muss ich selber entscheiden.

    heap-management und stl werd ich mal nachschlagen.

    so, hoffe das ich das jetzt alles soweit richtig verstanden habe:)

    aber muss zugeben ziehmlich interessantes thema



  • adonis schrieb:

    .

    was wo als stack definiert wird regelt das betriebssystem.

    Stackgrösse ist Linker-Option /STACK:reserve[,commit]



  • könnte man ein programm schreiben wo der stack
    erst während der laufzeit vollläuft? würde gern mal sehen was
    dann passiert:)



  • adonis schrieb:

    könnte man ein programm schreiben wo der stack
    erst während der laufzeit vollläuft?

    Während der Compilezeit kann der Stack des Programms nicht vollaufen 😉

    void murks()
    {
        int ary[1000];
        murks();
    }
    
    int main()
    {
        murks();
    }
    

    Der Array wäre nichtmal nötig, allerdings geht's dann schneller 😃



  • adonis schrieb:

    ...

    ...
    void main(void)
    {
    	DatenBank* myBank = new DatenBank;
    	progstart();
    	optionen();
    	delete myBank;
    }
    ...
    

    Hi,

    ein Hinweis noch: Wenn progstart(), optionen() oder irgendeine davon implizit aufgerufene Funktion (und sei sie noch so weit unten im System) eine exception wirft, wird delete nicht mehr aufgerufen. Dagegen hilft nur entweder "exceptionhandling mit try/catch" oder "scoping mit einem Stackobject" (auto_ptr o.ä.).
    Ich habe mir letzteres angewöhnt:

    template <typename PType>
    class AutoDelete {
    public:
    // Construction / Destruction
    	AutoDelete(PType _p) : p(_p) {}
    	~AutoDelete() { if(NULL != p) delete p;	}			
    private:
    // Attributes
    	PType p;
    // not to be implemented
    	AutoDelete(AutoDelete const &);
    	AutoDelete const & operator=(AutoDelete const &);
    ...
    };
    
    int main(int argc, char* argv[]) {
          DatenBank* myBank = new DatenBank;
          AutoDelete<DatenBank*> myBankScope(myBank); // kann man ab hier vergessen
          progstart();
          optionen();
          return 0;
    }
    

    muss aber jeder selbst wissen, ob einem das sowas wert ist und man mit den Einschränkungen (Kopierverbot) und Risiken (man kann natürlich myBank auch manuell löschen und AutoDelete dann auf den Hammer laufen lassen) leben kann/mag.
    (kann man mit zu schließenden Files etc. ebenso machen)

    Dein Beispiel ist allerdings etwas besonders:
    - Da das DatenBank-Objekt während der gesamten Programmlaufzeit existiert, würde das Betriebssystem den Speicher auch bei "vergessenem delete" höchstwahrscheinlich bei Programmende automatisch freigeben, aber
    - da "DatenBank" sehr komplex klingt, wird vermutlich beim "fachlichen Abräumen im Destruktor" noch einiges zu tun sein, was das Betriebssystem natürlich nicht übernehmen kann....

    Ich persönlich bin "Stackfan", weil es die Programme besser zu strukturieren "motiviert", die Dinge automatisiert, die letztlich nur lästige/fehleranfällige Tipparbeit sind und letztlich (IMHO) wartbarere und übersichtlichere Programme erzeugt.
    ... und an Speichergrenzen bin ich bislang noch nie gekommen - allerdings laufen unsere Programme auch auch "xGB-RAM-Kisten", bei denen es nicht so eine Rolle spielt und die wirklichen Datenmengen liegen im DB2 - Ausnahme: Speicherfresser durch "Heap-Programmierung". :p 😉

    Gruß,

    Simon2.


Anmelden zum Antworten