objekte löschen dauert zu lange



  • for ( unsigned int i=vector.size()-1; i > 0; --i ) { 
    			delete vector[i];
    	}	
    	vector.clear();
    

    Also ist so ein vector-container aus Zeigern. Deswegen muss man zuerst Objekte löschen, dann die zeiger selbst. Doch warum dauert das Löschen viel länger als das Anlegen von Objekten??? Gibt es da Tricks? Sind ja tausende von Objekte



  • Tricks gibts da schon, aber keiner ist universell verwendbar:

    1. Stack statt Heap
    Beispiel:

    IObject m_allObjects[10000];
    

    Vorteile:
    - sehr schnell
    - wird automatisch freigegeben

    Nachteile:
    - Größe beschränkt
    - verbraucht evtl. mehr Speicher als benutzt wird

    2. Memory-Pool
    Dabei werden die mit new erstellten Objekte möglichst nicht gelöscht, sondern in einen anderen vector (o. Ä.) geschoben, um sie später erneut zu verwenden. Wird dann ein Objekt benötigt, wird eins vom vector der unbenutzten genommen und zurückgesetzt (mit einer clear-Methode oder so), oder ggf. mit new erstellt.

    Vorteile:
    - Geschwindigkeit

    Nachteile:
    - macht nur Sinn, wenn oft Objekte entfernt und später weitere gebraucht werden

    3. "Zeigerlose Elemente"

    vector<IObject> m_objects;
    

    Vorteile:
    - könnte Zeit beim Löschen sparen (k. A. wieviel)

    Nachteile:
    - Zeiger auf die Elemente sind gefährlich



  • Hi,

    also so einfach mag ich das nicht glauben, dass das Löschen immer länger dauert als das Anlegen.
    Seeehr wesentlich dürfte dabei sein, was im Kon- und Destruktor getan wird.
    Das Betriebssystem/die Runtime hat meistens mit der Speicherfreigabe (beim Löschen) deutlich weniger zu tun als mit der Speicherreservierung (beim Erzeugen).

    Und wenn Du Deine Zeit in Kon-/Destruktoren verbrätst, helfen Dir alle anderen Tricks auch nichts ... die werden dann eben 1000-mal aufgerufen - egal wie.
    Auch bei der Stackvariante - allerdings da wohl eher zu Programmstart und -ende (übrigens leider auch dann, wenn sich zuer Laufzeit herausstellt, dass die Objekte gar nicht gebraucht werden).

    TyRoXx schrieb:

    ...
    3. "Zeigerlose Elemente"

    vector<IObject> m_objects;
    

    Vorteile:
    - könnte Zeit beim Löschen sparen (k. A. wieviel)

    Nachteile:
    - Zeiger auf die Elemente sind gefährlich

    War auch mein erster Gedanke ... allerdings werden höchstwahrscheinlich auch da die Objekte dynamisch angelegt - und wenn man es ungeschickt macht sogar deutlich öfter. Allerdings wird dabei wohl new[]/delete[] (also die Arrayvarianten genutzt) - es wäre vorstellbar, dass die ein wenig schneller sind als new/delete (wobei wie gesagt gar nicht sicher ist, dass die beiden das Problem sind).

    Gruß,

    Simon2.



  • Würde mich auch sehr wundern wenn da Zeit beim eigentlichen delete draufgeht.

    Ich gehe mal davon aus dass du dein Problem auch im Release-Modus beobachtet hast?

    Poste mal den Quelltext des Destruktors.

    Was ich schon des öffteren gesehen hab ist folgendes:

    ~DTor()
    {
       int time = time_now();
    
       while( ( time_now() - time ) < 200 )
       {
          warte_auf_ressource();
       }
    }
    

    Dann warten alle Objekte auf eine Ressource (z.B. ein Mutex) welche nicht freigegeben wird weil z.B. der entsprechende Thread grad arbeitet.

    Wenn das wirklich spürbar lange dauert kannst du dir auch mal die CPU-Last anschauen, wenn die auf 100 Prozent ist geht die Zeit wirklich für Arbeit und nicht fürs Warten drauf.

    Ansonsten solltest du mal über TyRoXx' Vorschlag mit dem MemoryPool nachdenken.
    Musst du riesige Felder wirklich freigeben oder kannst du den Zugriff nicht einfach kapseln sodass nach Außen kein Unterschied besteht aber du immer auf dem selben Speicher arbeitest?



  • rean schrieb:

    Was ich schon des öffteren gesehen hab ist folgendes:

    ~DTor()
    {
       int time = time_now();
    
       while( ( time_now() - time ) < 200 )
       {
          warte_auf_ressource();
       }
    }
    

    Dann warten alle Objekte auf eine Ressource (z.B. ein Mutex) welche nicht freigegeben wird

    Hier warten alle Objekte, völlig unabhängig davon, ob irgendwelche Ressourcen freigegeben sind.



  • xBlackKnightx schrieb:

    for ( unsigned int i=vector.size()-1; i > 0; --i ) {
      delete vector[i];
    }	
    vector.clear();
    

    Rückwärts mit unsigned int zählen ist gar nicht so einfach. 😉
    Hier vergisst Du das erste Element (i==0). Wenn Du aber die Schleife nach

    for ( unsigned int i=vector.size()-1; i >= 0; --i ) {
      delete vector[i];
    }
    

    abänderst, wird es eine Endlosschleife, da ein unsigned int ja nie negativ werden kann. Es müsste aber so gehen:

    for ( unsigned int i=vector.size(); i>0;) {
      --i;
      delete vector[i];
    }
    

    Gruß,
    SP



  • Verwende doch einen Iterator.



  • Sebastian Pizer schrieb:

    Rückwärts mit unsigned int zählen ist gar nicht so einfach.

    Ich glaube, daß es im vorliegenden Fall keinen Grund gibt, den Vektor von hinten nach vorne zu bearbeiten ...
    Also einfach:

    for(unsigned int i = 0; i < vector.size(); ++i)
       delete vector[i];
    


  • huch, es liegt wirklich an der for-schleife

    also der zusammenhang mit der rückwärtszählung und unsigned int?



  • TyRoXx schrieb:

    Tricks gibts da schon, aber keiner ist universell verwendbar:

    [u]3. "Zeigerlose Elemente"

    vector<IObject> m_objects;
    

    Vorteile:
    - könnte Zeit beim Löschen sparen (k. A. wieviel)

    Nachteile:
    - Zeiger auf die Elemente sind gefährlich

    die dritte Variante wollt ich nehmen aber es hat bereits zu tiefe Wurzeln und umbauen folgt mit vielen Fehlern naja.



  • huch, es liegt wirklich an der for-schleife

    Und wie kommst du darauf? Oder duerfen wir wild weiterraten ...



  • xBlackKnightx schrieb:

    huch, es liegt wirklich an der for-schleife

    also der zusammenhang mit der rückwärtszählung und unsigned int?

    Kann gut sein. Auf die Schnelle würde ich sagen, wenn Du nur ein Element im Vektor hast und dann diese Schleife beginnst, läufst Du genau in die von Sebastian Pizer aufgezeigte Falle ...
    Allerdings würde dann wohl das Programm eher abstürzen, als so lange zu laufen ...
    Wie dem auch sei, es gibt keinen (ersichtlichen) Grund, den Vektor von hinten nach vorne zu durchlaufen, und vielleicht kannst Du auch einen signed int als Schleifenzähler nehmen? Dann könntest Du bei Deiner Methode bleiben und 'i < 0' als Abbruchbedingung nehmen.



  • Sebastian Pizer schrieb:

    Rückwärts mit unsigned int zählen ist gar nicht so einfach. 😉
    Hier vergisst Du das erste Element (i==0). Wenn Du aber die Schleife nach

    for ( unsigned int i=vector.size()-1; i >= 0; --i ) {
      delete vector[i];
    }
    

    abänderst, wird es eine Endlosschleife, da ein unsigned int ja nie negativ werden kann. Es müsste aber so gehen:

    for ( unsigned int i=vector.size(); i>0;) {
      --i;
      delete vector[i];
    }
    

    Wenn's auf der Plattform einen typischen Underflow gibt
    assert( size_t(0)-1 == std::numeric_limits<size_t>::max() );
    , geht auch
    for ( size_t i=vector.size()-1; i<vector.size(); --i )
    .

    PS: Unter der Voraussetzung vector.size() < std::numeric_limits<size_t>::max()-1



  • Badestrand schrieb:

    Wenn's auf der Plattform einen typischen Underflow gibt [...]

    Das sollte für unsigned -Typen doch garantiert sein, oder?



  • Nexus schrieb:

    Badestrand schrieb:

    Wenn's auf der Plattform einen typischen Underflow gibt [...]

    Das sollte für unsigned -Typen doch garantiert sein, oder?

    Keine Ahnung, bin nicht so fit mit dem Standard 🙂 Ich schlag mal in einem neueren Draft nach..

    edit: Finde nichts dazu.


  • Administrator

    C++ Standard 14882:2003 - 3.9.1 Fundamental types - Abschnitt 4 schrieb:

    Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.

    http://en.wikipedia.org/wiki/Modular_arithmetic

    Also würde ich sagen, dass es sehr genau definiert ist, nicht? Zu Overflow steht es sogar unten explizit als Notiz. Explizit zu Underflow steht allerdings nichts, sollte aber eigentlich aus der Definition hervorgehen.

    Grüssli


Anmelden zum Antworten