Speicherverbrauch shared_ptr und normaler *



  • DocShoe schrieb:

    @Printe:
    Du vergisst vermutlich die echten Stringdaten.

    Was meinst du damit? Eigentlich wollte ich genau darauf hinaus: MyClass enthält nur die Verwaltungsstrukturen, nicht die Stringinhalte selber. Und die Verwaltungsstrukturen von CString bzw. std::string erklären nicht den Verbrauch von 1,2 bzw. 2 GB Speicher, nicht bei einer Million Objekten.



  • Ich weiß, ich bin selber schuld 😃

    Ich muss Printe hier recht geben. In 800 MB passt echt viel String, da scheint irgendwas komisch zu sein.

    Ich befürchte nach wie vor, dass irgendwo wild Daten kopiert werden und mehrfach vorliegen.

    Die CString Implementierung verwendet intern ein Reference Counting um unnötige Kopien zu vermeiden

    As of MFC version 4.0, when CStringT Class objects are copied, MFC increments a reference count rather than copying the data. This makes passing parameters by value and returning CString objects by value more efficient. These operations cause the copy constructor to be called, sometimes more than once. Incrementing a reference count reduces that overhead for these common operations and makes using CString a more attractive option.

    As each copy is destroyed, the reference count in the original object is decremented. The original CString object is not destroyed until its reference count is reduced to zero.

    You can use the CString member functions CSimpleStringT::LockBuffer and CSimpleStringT::UnlockBuffer to disable or enable reference counting.

    https://msdn.microsoft.com/en-us/library/aa300688(v=vs.60).aspx

    Aber wenn das ein Unterschied von 800 MB ausmacht, ist da noch was anderes im Argen.



  • @SeppJ

    Korrekte Rechtschreibung und Grammatik sind das sprachliche Äquivalent zu einer Dusche und gepflegter Kleidung.

    Der Umgangston gehört auch dazu. Ich habe kein Problem mit Kritik aber du bist ständig nur am beleidigen: ->

    Mitdenken tust du auch nicht

    Wer dir noch weiter helfen will, ist selber schuld!

    Und dann auch andere noch dazu anstiften.

    Ich klinke mich hier aus

    Das ist hier der einzige vernünftige Satz von dir.



  • sizeof (myClass.myStdString[0]) und
    sizeof (myClass.myCString[0])

    liefern im übrigen beidesmal eine 1



  • Ihr habt aber recht irgendwo gehen 800MB flöten da passt viel mString rein.

    Ich kann gerne meine "total falsche Struktur" offen legen die der seppl immer wieder kritisiert.

    es handelt sich zum einen um eine struct
        struct ITcAdsSymbol
        {
            string			comment;
            AdsDatatypeId	        datatype;  //enum
            long			indexGroup;
            long			indexOffset;
            string			name;
            string			shortName;
            int				size;
            int				subSymbolCount;
            string			type;
        };
    

    und um eine Klasse die zum einen eine Referenz auf die struct hat. Desweiteren eine map die wiederum die Kinder darstellen. Objekte der selben Klasse.


  • 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.


Anmelden zum Antworten