Speicherverbrauch shared_ptr und normaler *



  • OT

    Schlangenmensch schrieb:

    Generell shared pointer zu verwenden, schön Referenzen mitzählen und sich halt keine Gedanken um Ownership zu machen ist ein einfacher Weg aber kein schöner.

    Diese Kritik hört man oft.

    Lustigerweise habe ich in 20 Jahren Arbeiten mit C++ mehr Probleme erlebt die dadurch verursacht wurden dass auf shared_ptr verzichtet wurde als Probleme die von übertriebenem shared_ptr Einsatz kamen.

    Und jedes mal wenn ich "keine Gedanken um Ownership zu machen" als quasi Argument gegen shared_ptr lese denk' ich mir meinen Teil.

    /OT



  • ps:

    booster schrieb:

    4. Ist eine std::map wirklich der richtige Container für deinen Usecase?
    Ich benötige die map mit einem string als Key um nach bestimmten Objekten zu suchen. Denke schon, das hier map das richtige ist.

    Alternativen könnten sein:
    std::unordered_map
    boost::flat_map



  • Spart die std::unordered_map platz.

    Aber bevor wir noch lange über Pointer reden. Habe den Platzverbraucher gefunden.

    Die Daten selbst bestehen aus 9 Variablen. Darunter sind 4 strings.

    Früher waren die strings CStrings von MFC. Nun habe ich diese unter anderem auch auf std::strings umgestellt.

    sizeof(CString) = 4
    sizeof(std::string) = 28

    Bei 4 strings sind das 96 Bit mehr.
    Bisher 56 bits nun 152. Das ist natürlich das dreifache. Und mein erhöhter Speicherverbrauch erklärbar. An der falschen Stelle gesucht. Aber nun was über smart pointer gelernt.


  • Mod

    Leider hast du aber überhaupt nichts über strings gelernt und guckst daher an der völlig falschen Stelle. Denk mal drüber nach, wie so ein String wohl funktioniert. Wenn ich da "12345" drin speichere, wie kommt der dann mit 4 Bytes aus?

    Und dir sollen wir nun einfach glauben, dass deine Datenstruktur so richtig ist, bloß weil du uns das sagst 🙄



  • Wieso soll nun meine Datenstruktur nicht stimmen. Was hat das nun mit dem string zu tun?????

    Kannst du auch mal ne Lösung geben als immer alles schlecht zu machen und einen zu kritisieren.

    Wenn ich siezof(myClass->mystring) aufrufe erhalte ich 4
    Wenn ich siezof(myClass->myCString) aufrufe erhalte ich 28

    und das egal wieviel in dem string steht.



  • Und das glaubst du? Wenn du in einem CString "Hello World" ablegst hat er auch nur eine Größe von 4 Byte? Oder sind diese 4 Byte möglicherweise nur ein Zeiger auf den Speicherbereich, wo die tatsächlichen Daten stehen?



  • dann helft mir doch mal auf die Sprünge

    wenn ich sizeof(myclass) mache erhalte ich in ersterem Fall 56
    und in zweiteren 152

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

    Wo liegt dann das Problem



  • Dies nennt sich small string optimization (SSO), d.h. einige std::string Implementationen haben einen kleinen Puffer (ca. 16-20 chars) - u.a. beim MSVC.

    @booster: Was SeppJ und DocShoe dir sagen wollen, ist, daß sizeof(std::string) nur den statischen Speicherplatz angibt - zur Laufzeit wird dann (ohne SSO) der eigentliche String auf dem Heap reserviert.



  • DNKpp schrieb:

    @printe
    du teilst also jedes mal wenn du einen pointer raus gibst gleich die kompletten Besitzverhältnisse?

    Indem du einen Pointer rausgibst über ein öffentliches GetPointerToObject-Interface, teilst du den Besitz de facto, denn was der Empfänger damit anfängt, ist nicht mehr unter deiner Kontrolle. Also ist es nur richtig, wenn der Code das widerspiegelt. Ja, wenn ich Pointer rausgebe und nicht weiß, an wen, dann teile ich den Besitz (oder gebe ihn ganz ab, je nachdem).

    Wenn du Raw-Pointer verteilst auf Objekte, die du in Smartpointern verwaltest (egal ob unique oder shared), dann lügst du dir selber einen vor, denn die ganze Besitz- und Lebenszeitkontrolle, die in den Smartpointern steckt, stimmt nicht mehr.

    In einem lokalen, überblickbaren Kontext kann man shared_ptr::get gefahrlos verwenden. Aber nicht als Rückgabe an jeden X-beliebigen.



  • booster schrieb:

    dann helft mir doch mal auf die Sprünge

    wenn ich sizeof(myclass) mache erhalte ich in ersterem Fall 56
    und in zweiteren 152

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

    Wo liegt dann das Problem

    Das Problem ist, dass das den Speicherverbrauch eben nicht erklärt. Rechne doch selber nach:

    56 Bytes pro Objekt mal 1 Million Objekte = 56 MB. Das ist Lichtjahre von 1,2 GB entfernt. Für 152 Bytes pro Objekt gilt das gleiche.

    Dein Speicherproblem muss eine andere Ursache haben.

    Was enthalten denn die 4 Strings, die MyClass enthält? Wie lang sind die Nutzdaten?

    Könnte es sein, dass die eine String-Implementierung 8-Bit-Zeichen benutzt und die andere breitere? Vergleich doch mal
    sizeof (myClass.myStdString[0]) und
    sizeof (myClass.myCString[0]).



  • Sind die Strings denn alle unterschiedlich? Kannst du eine Lookup-Tabelle benutzen und in deiner Datenstruktur nur einen Index statt des Strings speichern? Zeig doch bitte mal deine Struktur und schreib ein bisschen was dazu.

    @Printe:
    Du vergisst vermutlich die echten Stringdaten.


  • Mod

    booster schrieb:

    Wieso soll nun meine Datenstruktur nicht stimmen. Was hat das nun mit dem string zu tun?????

    Deine Beschreibungen waren allesamt falsch oder inkonsistent, alles deutet darauf hin, dass deine Datenstrukturen sowohl falsch gewählt als auch falsch umgesetzt sind. Doch du bestehst darauf, dass das natürlich alles richtig ist, denn es kommt von dir und alle anderen sind dumm, wenn sie es wagen, dich zu kritisieren. Und dann bringst du solche Dinge wie deine Beobachtung mit dem String, die zweifelsfrei beweisen, dass du absolut keine Ahnung von dem hast, wovon du hier sprichst. Da soll man deinen Versicherungen glauben, dass mit den Datenstrukturen alles in Ordnung sei? Du hast offensichtlich gar nicht die Kompetenz dies zu beurteilen.

    Wenn ich siezof(myClass->mystring) aufrufe erhalte ich 4
    Wenn ich siezof(myClass->myCString) aufrufe erhalte ich 28

    und das egal wieviel in dem string steht.

    Mitdenken tust du auch nicht. Denn sonst wärst du über diese Beobachtung vielleicht so langsam drauf gekommen, dass sizeof absolut nichts mit der Speicherbelegung durch ein Objekt zu tun hat. Schließlich hat deine map auch ein sizeof von wenigen Bytes, obwohl du dort mehrere Gigabyte Speicherbelegung vermutest (Betonung auf "vermutest", denn deinen Beobachtungen und Schlussfolgerungen kann man nicht mehr glauben).

    Kannst du auch mal ne Lösung geben als immer alles schlecht zu machen und einen zu kritisieren.

    Ach! Deshalb habe ich auch nur vor 5 Seiten schon geschrieben, was nötig ist, damit man dir helfen kann. Du hast nichts davon geliefert und machst stattdessen nur Leute dumm an, wenn sie dir helfen wollen. Ich klinke mich hier aus. Wer dir noch weiter helfen will, ist selber schuld!



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


Anmelden zum Antworten