Speicherverbrauch shared_ptr und normaler *



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

    ... sagt wer? Ich finde einfache Wege per se schön. So schön, dass ich nach komplizierteren erst bei eindeutig festgestelltem Bedarf suche.

    Der sauberste Weg hier, wäre wahrscheinlich ein Iterator auf das Map Element rauszugeben ...

    Nein. Es ist sogar äußerst unsauber, jemandem, der lediglich ein Objekt anfragt, einen Iterator zu schenken, denn:
    1. will derjenige gar nicht den Iterator, sondern nur das, was in iterator->second steckt.
    2. geht es ihn nichts an, dass es sich um eine Map handelt. Gibt man dieses Wissen öffentlich bekannt, kann man den Container nicht mehr ohne weiteres ändern.
    3. bekommt derjenige damit die Macht, nicht nur das gewünschte Objekt abzuholen, sondern Stück für Stück den ganzen Containerinhalt.



  • booster schrieb:

    ok aber anstelle meiner shared_ptr für parent usw. könnte ich ja dann wie erwähnt weak_ptr benutzen. Und auch als Rückgabe meiner find Methode oder?

    Wenn du mit weak_ptr arbeitest muss du halt immer mit lock() ein shared ptr erzeugen, wenn du mit dem Pointer arbeitest.



  • Um es noch einmal zusammenzufassen:
    Es gibt mehrere gangbare Wege. Welcher davon der richtige und für deinen Zweck beste ist, musst du selbst entscheiden, da wir deinen Anwendungsfall nicht genug kennen. Im übrigen stellen wir deswegen einfach mal die gesamte Datenstruktur in Frage 😉



  • booster schrieb:

    ok aber anstelle meiner shared_ptr für parent usw. könnte ich ja dann wie erwähnt weak_ptr benutzen.

    Ja, weil du sonst geschlossene Referenz-Kreise baust. Das ist der Grund, weshalb es weak_ptr gibt.

    Und auch als Rückgabe meiner find Methode oder?

    Wozu soll das gut sein? Die Map hält einen shared_ptr, find erzeugt einen weak und reicht den raus, und der Empfänger muss erst mal wieder einen shared draus machen, um damit was anfangen zu können?



  • @printe
    du teilst also jedes mal wenn du einen pointer raus gibst gleich die kompletten Besitzverhältnisse?
    Ein shared_ptr ist nicht einfach nur mal eben einen counter incrementieren. Da steckt ein gewisser sync overhead drin, der nicht zu verarchten ist.



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


Anmelden zum Antworten