Speicherverbrauch shared_ptr und normaler *


  • Mod

    booster schrieb:

    der seppl

    Wow. Du bist bestimmt der Held in deiner Kindergartengruppe, mit deiner messerscharfen Zunge für Spitznamen.



  • booster schrieb:

    Wenn ich nun wieder auf CString umstelle lande ich wieder bei 1,2GB Speicherauslastung.

    An der grösseren "Grundgrösse" der Strings wird es eher nicht liegen wie schon andere geschrieben haben. Könnte daran liegen dass std::string over-allocation betreibt. Keine Ahnung ob das üblich ist, aber erlaubt ist es glaube ich - könnte also durchaus sein dass einige Standard-Library Implementierungen das so machen.

    Wenn du den Platzverbrauch deiner Strings optimieren willst, dann gäbe es allerdings andere Möglichkeiten.
    Wenn es bei den String viele Duplikate gibt, dann könntest du ein Zentrales std::set<std::string> machen wo du alle Strings reinsteckst, und in den Datenstrukturen dann bloss noch einen std::string const* ablegen.

    Wenn es keine/kaum Duplikate gibt gibt es auch Möglichkeiten, das wird aber etwas komplizierter.



  • ps: Wenn du auf Grösse Optimieren willst ordne die Member der Grösse nach:

    struct ITcAdsSymbol
        {
            string			comment;
            AdsDatatypeId	        datatype;  //enum
            long			indexGroup;
            long			indexOffset;
            string			name;
            string			shortName;
            int				size;
            int				subSymbolCount;
            string			type;
        };
    
    // =>
    
        struct ITcAdsSymbol
        {
            AdsDatatypeId	        datatype;  //enum
            int				size;
            int				subSymbolCount;
            long			indexGroup;
            long			indexOffset;
            string			comment;
            string			name;
            string			shortName;
            string			type;
        };
    

    Wird nicht mega-viel bringen aber ein bisschen was ist damit vermutlich drinnen. (Bzw. auf 64 Bit kann sogar sein dass es gar nix bringt, aber es schadet vermutlich auch nicht.)



  • struct ITcAdsSymbol
    {
         AdsDatatypeId   datatype;  //enum
         int             size;
         int             subSymbolCount;
         long            indexGroup;
         long            indexOffset;
         string          comment;
         string          name;
         string          shortName;
         string          type;
    };
    
    =>
    
    #pragma pack( push, 1 )
    struct ITcAdsSymbol
    {
         AdsDatatypeId    datatype;  //enum
         unsigned short   size;               // möglichst kurze Datentypen benutzen,
         unsigned short   subSymbolCount;     // ich gehe davon aus, dass die alle in
         unsigned short   indexGroup;         // einen unsigned short passen, evtl sogar
         unsigned short   indexOffset;        // in einen unsigned char.
         string           comment;
         string           name;
         string           shortName;
         SomeType::Type_t type;                // Typ nicht als Namen speichern, sondern 
                                               // als enum oder id. Die dann in einer Tabelle nachschlagen
    };
    #pragma pack( pop )
    

    Die Pragma Anweisung verhindert Padding, was zu kleineren Strukturgröße führt, aber den Zugriff auf die Member etwas verlangsamt. Ich glaube aber, dass nicht die Strukturgröße selbst das Problem ist, sondern die string-Daten, die in den einzelnen strings stecken. Vielleicht kannst du da was rausholen, wenn du die iwie verkürzen kannst. Oder du lagerst die Namen extern aus und lädst sie nur bei Bedarf in den Hauptspeicher. Spontan fiele mir das sowas wie SQLite3 ein, wo du eine Datenbank auf der Festplatte liegen hast, aus der du dann Namen für einzelne Objekte nachladen kannst.



  • @seppl: oh man was bist du denn für ein typ. Und dann auch noch flache Witze machen.

    @an alle ausser seppl
    Ich habe die Struktur eigentlich übernommen von einer c# kauf Komponente.
    Gut kann sein dass die auch Fehler gemacht haben aber in unsere "Kindergartengruppe" (10 Entwickler) hatten wir an der Struktur so erst mal nicht auszusetzen. Gut verbessern kann man immer.

    Ich habe das ganze in c++ nachprogrammiert. Wie gesagt anfangs mit Rohzeigern und CString.
    Bei der Umstellung auf shared_ptr und string trat der angegebene Fehler auf. Da war erst mal naheliegend den Fehler bei den pointern und dann beim string zu suchen.

    Die c# Komponente steigt im übrigen auch auf 2 GB an.

    Könnte es eventuell an der Baumstruktur liegen? Wenn jedes Objekt nochmals eine map beinhaltet die jeweils wiederum ein string als key beinhaltet.



  • booster schrieb:

    sizeof (myClass.myStdString[0]) und
    sizeof (myClass.myCString[0])
    liefern im übrigen beidesmal eine 1

    OK, dann sind wide-character-Strings als mögliche Ursache ausgeschieden.



  • Ich wäre an deiner Stelle vorsichtig, booster.
    SeppJ weiß, wovon er spricht, und ich kann seine Reaktion durchaus nachvollziehen. Du provozierst diese Reaktion mit genau dem Verhalten, was SeppJ dir vorwirft: Du lieferst falsche oder unpräzise Informationen, oft erst auf mehrmaliges Nachfragen. Bis dahin ist alles lesen aus dem Kaffeesatz.
    Keiner hier im Forum bekommt irgendeine Vergütung für die Lösung deines Problems, das passiert auf freiwilliger Basis. Und wenn du es den potenziellen Helfern schwer machst haben die irgendwann keine Lust mehr.



  • @DocShoe

    Die Typen sind so vorgegeben und kommen von er Schnittstelle zu SPS.
    Indexgroup und Indexoffset sind long Werte und sie auch ziemlich groß.

    Und "type" ist nicht der eigentlich Datentyp. Der eigentliche Typ steht in Datatype. Da habe ich schon ein enum draus gemacht.

    Also an der Struktur kann ich außer der Reihenfolge nichts ändern.

    Und ich denke nicht für den Speicherverbrauch verantwortlich.



  • Natürlich kannst du an der Datenstruktur was ändern. Du musst halt die Daten konvertieren.

    Summier doch mal die Größen der string-Nutzdaten auf und gib sie aus.

    map<string,unsigned long long> MemUsage;
    for( const auto& val : MapData )
    {
       MemUsage["comment"]   += (sizeof( string ) + val.comment.size);
       MemUsage["name"]      += (sizeof( string ) + val.name.size);
       MemUsage["shortname"] += (sizeof( string ) + val.shortname.size);
       MemUsage["type"]      += (sizeof( string ) + val.type.size);
    }
    

    Und jetzt guckste dir an, welche strings wie viel Speicher brauchen, dann haste nen Anhaltspunkt, wo du ansetzen kannst.



  • SeppJ weiß, wovon er spricht, und ich kann seine Reaktion durchaus nachvollziehen

    Das mag schon sein. Aber der Umgangs ton geht mal gar nicht. Man ist kein guter Moderator nur weil man sich im Bereich gut auskennt aber sich nicht unter Kontrolle hat.

    Ich habe hier nie beleidigt. Vielleicht hier und da mal etwas falsch gefragt oder falsch umschreiben. Nur weil ich nicht gleich alles offen legen wollte und der einfach halber manches zuerst weggelassen habe heißt das doch nicht dass ich mich nicht auskenne.

    Für die freiwillige Hilfe bin ich ja auch sehr dankbar. Aber so wie der seppl hier hat sich von den anderen keiner Verhalten.



  • booster schrieb:

    ...
    Und "type" ist nicht der eigentlich Datentyp. Der eigentliche Typ steht in Datatype. Da habe ich schon ein enum draus gemacht.
    ...

    Genau das ist der Punkt. Du zeigst uns Code, den du nicht benutzt, und wir sollen was dazu sagen 👎



  • booster schrieb:

    es handelt sich zum einen um eine struct
        struct ITcAdsSymbol
        {
            string			comment;
            string			name;
            string			shortName;
            string			type;
        };
    

    OK. Ein Kommentarfeld - das klingt nach potentiell sehr langen Strings, die aber nur sehr gelegentlich gebraucht werden. Lazy-loading nur bei Bedarf könnte hier ein Ausweg sein.

    Das Problem, booster, ist, dass du anfangs behauptet hast, du hättest nur raw-pointer durch shared_ptr ersetzt und damit wäre dein Speicherverbrauch von 1,2 auf über 2 GB explodiert.

    Später kam dann raus, deine Datenstruktur ist um einiges komplizierter als eingangs beschrieben (flache und tiefe Map) und du hast gleichzeitig mit dem Zeigerumbau auch CString durch std::string ersetzt. Inzwischen sind wir auf der 8. Seite und noch nicht wirklich weiter, weil scheibchenweise immer neue Details bekannt werden. Dass so mancher da die Geduld verliert, ist vielleicht nachvollziehbar.



  • @DocShoe

    Du zeigst uns Code, den du nicht benutzt, und wir sollen was dazu sagen

    Was soll das jetzt? Ich habe doch die Struktur gezeigt. Der Datentyp steht doch ganz oben:

    AdsDatatypeId   datatype
    

    Ich habe doch gar nicht gesagt dass ich den typ nicht nutze. In "type" steht auch ein Name drin. Dass die den typ genannt haben ist ja jetzt sicher keine Ursache für das Speicherproblem!

    Natürlich kannst du an der Datenstruktur was ändern. Du musst halt die Daten konvertieren.

    Wieso sollte ich? Es macht doch keinen Sinn einen long in einen unsigned short zu konvertieren.



  • Ächz

    Einmal nicht, vier Millionen mal vielleicht schon.



  • @Printe
    an das Kommentar Feld habe ich auch schon gedacht und erst mal aus kommentiert aber hat auch noch nicht viel gebracht.

    Gut dass ich anfangs gesagt habe dass ich nur die pointer Geschichte umgebaut habe lag daran dass ich an den string schlicht nicht mehr gedacht habe.

    Und das mit der Flachen bzw Baumstruktur habe ich nicht erwähnt da ich daran ja nichts geändert habe. Die Baum + Flache Strukur war ja vorher schon vorhanden.

    Man soll ja versuchen das Problem so weit wie möglich einzukreisen bevor man nachfragt.



  • Jetzt mal was ganz Anderes:
    Brauchst du wirklich 1.000.000 Objekte gleichzeitig im Speicher? Reicht es nicht aus, nur relevante Daten im Speicher zu halten und bei Bedarf nachzuladen? Woher kommen denn die Daten und wie schnell kannst du auf die Originaldaten zugreifen/nachladen?



  • Ächz

    Einmal nicht, vier Millionen mal vielleicht schon.

    ????????????

    Ein Wert von IndexOffset ist z.B. 3032838

    Wie soll ich das nun in einen unsigned shor umwandeln.

    Genau das ist doch der Punkt wieso ich meine Struktur nicht offen legen wollte.
    Liegt es jetzt an dem long oder short wieso ich einen erhöhten Speicherverbrauch von 800MB habe. Und das noch dazu dass es vorher ein long war und danach immer noch ein long ist.



  • Brauchst du wirklich 1.000.000 Objekte gleichzeitig im Speicher

    Ich brauche die Daten beim Start der Applikation. Ich lade alle Informationen in den Speicher. Damit ich dieser zu Erzeugung anderer Objekte zur Verfügung habe. Danach kann man den Speicher wieder aufräumen.

    Natürlich könnte man anfangs nur mal z.B. nur den "Namen" des Objekts in den Speicher laden und nachher nur von den wirklich benötigten Objekten den Rest.

    Aber das laden aus der SPS ist nicht sehr performant. Darum war die bisher die Lösung alles bei Start zu laden.



  • booster schrieb:

    Genau das ist doch der Punkt wieso ich meine Struktur nicht offen legen wollte.
    Liegt es jetzt an dem long oder short wieso ich einen erhöhten Speicherverbrauch von 800MB habe. Und das noch dazu dass es vorher ein long war und danach immer noch ein long ist.

    Achso. Und ich dachte schon, wir wollten den Gesamtspeicherverbrauch senken, um mehr Platz für die Nutzdaten zu haben. Zugegebenermaßen sind 8 MB bei 800 MB nur 1%, aber weiß der Geier, wieviele Instanzen von ITcAdsSymbol es tatsächlich gibt.

    Habe dein Programm so richtig verstanden:

    1. Einlesen der Daten aus der SPS
    2. Erzeugen von anderen Daten aus den SPS-Daten
    3. Löschen der SPS-Daten aus dem Speicher

    ?



  • @DocShoe

    Erst mal ging es mir den erhöhten Speicherverbrauch zu erklären. Deshalb habe ich meine Erklärung auf das wichtigste reduziert. Und das war zunächst der pointer dann um den string.

    Klar wäre es dann schön auch den Gesamtverbrauch zu senken. Aber ich denke wenn wir wissen woher der erhöhte Speicherverbrauch herkommt lässt sich auch der Gesamtverbrauch erklären.

    Und da versteh ich es nicht wieso man Dinge wie den typ anmeckert nur weil ich den nicht erklärt habe. Oder wieso man nun aus nem long einen short machen will obwohl hier der Wert den range des short übersteigt.

    Habe dein Programm so richtig verstanden:

    1. Einlesen der Daten aus der SPS
    2. Erzeugen von anderen Daten aus den SPS-Daten
    3. Löschen der SPS-Daten aus dem Speicher

    Ja so der Teilabschnitt im Programm um den es sich gerade dreht.

    Aber nochmals kann es vielleicht sein dass der Speicherverbrauch daher rührt dass die Objekte wiederum selbst eine Map mit string als key haben?


Anmelden zum Antworten