Speicherverbrauch shared_ptr und normaler *



  • Also wenn 3MB auf 1.2GB aufgebläht werden gibt es da sicher Optimierungspotenzial.

    Wie viele Elemente hat denn so eine map? Sind das eher 10 oder eher 100? Du hast ja schon bemerkt, dass die map overhead hat. Wenn ich dich richtig verstanden habe brauchst du die Daten nur zum Aufbauen anderer Daten, sie sind also read-only. Statt einer map könntest du auch einen sortierten vector nehmen und mit binärer Suche suchen, dann hast du einen vector mit wenig Overhead und trotzdem schnellen Zugriff. Auf smart pointer könntest du dann ebenfalls komplett verzichten und die Kindbäume mit rohen Zeigern befüllen. Das sollte einiges bringen.



  • Na also, endlich kommen die interessanten Informationen. Jetzt hab ich noch ein paar Verständnisfragen:

    1. Was verwendest du als Key? Das, was in ITcAdsSymbol::name steht?
    2. Der Unterschied zwischen der flatCollection und der treeCollection ist was genau? Das hast du bestimmt schon mal irgendwo erwähnt, aber vielleicht kannst du es, mit den Deklarationen vor der Nase, nochmal kurz auf den Punkt bringen?
    3. Ist jedes Symbol und jedes Subsymbol genau einmal in den Collections? Oder sind die mehrfach vorhanden? Wenn ja, nach welchen Regeln?
    4. AdsSymbol enthält eine Referenz auf ein ITcAdsSymbol-struct. Warum ist das eine Referenz, und wo befinden sich die tatsächlichen Struct-Daten? Die fehlen uns nämlich noch.



  • Hallo Printe

    1. Ja

    2. Die TreeCollection ist genau so aufgebaut wie die Variablenstruktur in der SPS. Also es gibt etwa 1000 Variablen auf oberster ebene. Alle anderen sind dann wiederum Kinder und Enkelkinder usw. also SubSymbols genannt.
    In der FlatCollection liegen alle Variablen bis in tiefster Ebene auf selber Ebene.

    3. Also jedes Symbol ist genau einmal vorhanden.

    Der Name (im Gegensatz zum short Name) ist aber zusammengesetzt.
    Also z.B.
    Oberste Varible heißt "MyFunctionBlock"
    Dann heißt die Variable darunter "MyFunctionBlock.MyStruct"
    und die wieder darunter
    "MyFunctionBlock.MyStruct.MyArray"

    4. Schreibfehler ist keine Referenz. Sorry das & ist zu viel.



  • booster schrieb:

    Der Name (im Gegensatz zum short Name) ist aber zusammengesetzt.
    Also z.B.
    Oberste Varible heißt "MyFunctionBlock"
    Dann heißt die Variable darunter "MyFunctionBlock.MyStruct"
    und die wieder darunter
    "MyFunctionBlock.MyStruct.MyArray"

    Kommen denn diese zusammengesetzten Namen original aus der SPS? Oder bildest du die in der Software, indem du auf jedem Weg durch den Baum die Namen aufsammelst und hintereinanderstellst?

    Verstehst du den Unterschied?

    Im zweiten Fall bildest du selber Namen wie "MyFunctionBlock.MyStruct.MyDings", "MyFunctionBlock.MyStruct.MyBums", "MyFunctionBlock.MyStruct.MyBlah" usw., die es in den Originaldaten so nicht gibt. Der Teil "MyFunctionBlock.MyStruct" wird dabei immer wieder dupliziert. Das bläht den Speicherbedarf schon merklich auf ...

    Außerdem hast du wegen flat und tree schon mal alles doppelt.


  • Mod

    booster schrieb:

    1. Ja

    Dann ist set die Datenstruktur, die du suchst, nicht map. => doppelte Strings vermieden

    booster schrieb:

    2. Die TreeCollection ist genau so aufgebaut wie die Variablenstruktur in der SPS. Also es gibt etwa 1000 Variablen auf oberster ebene. Alle anderen sind dann wiederum Kinder und Enkelkinder usw. also SubSymbols genannt.
    In der FlatCollection liegen alle Variablen bis in tiefster Ebene auf selber Ebene.

    Was heisst selbe Ebene? Es ist relativ einfach, einen Iterator zu schreiben, der den gesamten Baum durchlaufen kann. => Speicherverbrauch halbiert.

    booster schrieb:

    3. Also jedes Symbol ist genau einmal vorhanden.

    Der Name (im Gegensatz zum short Name) ist aber zusammengesetzt.
    Also z.B.
    Oberste Varible heißt "MyFunctionBlock"
    Dann heißt die Variable darunter "MyFunctionBlock.MyStruct"
    und die wieder darunter
    "MyFunctionBlock.MyStruct.MyArray"

    name ist einfach zusammengesetzt aus shortName der parents plus short Name des Elements, getrennt duch Punkte? Dann ist das völlig überflüssige Speicherverschendung. Unter diesen Bedingungen ist dein FindSymbol auch doppelt ineffizient (einerseits O(N) statt O(log N) beim Durchlaufen des Baumes, und andererseits sind die zu vergleichenden Strings unnötig lang).

    Ich sehe auch keinerlei Notwendigkeit hier überhaupt irgendeine Form von Zeigern einzusetzen. Das ganze könnte also ungefär so aussehen

    class AdsSymbol
    {
        ITcAdsSymbol symbol;
    
        AdsSymbol(const AdsSymbol&) = delete;
        AdsSymbol& operator=(const AdsSymbol&) = delete;
        AdsSymbol(AdsSymbol&&); // ggf. Zeiger in _subSymbols auf parent anpassen
        AdsSymbol& operator=(AdsSymbol&&);
    
        struct SymbolCompare {
            template <typename T>
            bool operator()(T&& x, const AdsSymbol& y) const { return std::forward<T>(x) < y.symbol.shortName; }
            template <typename T>
            bool operator()(const AdsSymbol& x, T&& y) const { return x.symbol.shortName < std::forward<T>(y); }
            bool operator()(const AdsSymbol& x, const AdsSymbol& y) const { return x.symbol.shortName < y.symbol.shortName; }
            using is_transparent = int;
        };
        mutable set<AdsSymbol, SymbolCompare> _subSymbols;
    ...
        const AdsSymbol* FindSymbol(const string& name) const { return FindSymbol(string_view(name)); }
        const AdsSymbol* FindSymbol(string_view name) const
        {
            if (name == symbol.shortName)
                return this;
    
            if (symbol.shortName.size() <= name.size() || symbol.shortName == name.substr(0, symbol.shortName.size()) || name[symbol.shortName.size()] != '.')
                return nullptr;
    
             return FindSymbolImpl(substr(symbol.shortName.size()+1));
         }
         const AdsSymbol* FindSymbolImpl(stringview name) const
         {
             auto end = find(name.begin(), name.end(), '.');
             auto subSym = _subSymbols.find(name.substr(0, end));
             if (subSym == _subSymbols.end())
                 return nullptr;
             if (end == name.end())
                 return &*subSym;
             return subSym->FindSymbolImpl(name.substr(end+1));
         }
    };
    
    AdsSymbol tree_root;
    


  • @printee

    Ja ich versteh den Unterschied. Aber ich setzt die Namen nicht zusammen.
    In Name steht immer der gesamte Name drin. Also zusammengesetzt mit ".", Da mache ich nichts, das kommt direkt so von der SPS

    In shortName steht dann nur der eigene Name ohne die Namen der Eltern.

    Ich habe auch schon den shortName als key für die map verwendet und mal die FlattCollection für einen Test komplett weggelassen. Und der Speicher lief auch bis auf 2GB voll.



  • @camper

    1. Was dann? Klar ist der String dann doppelt vorhanden. Aber ich benötige den String ja als key

    2. Natürlich kann ich da einen Iterator schreiben der den Baum durchläuft. Das hatte ich ja schon geschreiben. Es war nur eine Frage der Effizienz ob ein Iterator schneller ist oder die Flatt halt einfach ab Programmstart aufzubauen.

    Aber wie gesagt. Die Flatt habe ich für einen Test weggelassen. Selber Speicherverbrauch.

    3. Siehe Antwort vorher. Wenn ich nur den shortName als Key nehme beliebt auch hier der Speicherverbrauch gleich hoch. In Name ist so schon der komplette Name drin.

    4. Danke für den Programmcode. Muss mir den erst mal genau anschauen. Aber wie gesagt mein Problem scheint nicht an den Pointern und an den zu langen strings gelagert zu sein.



  • Mir fällt gerade was anderes auf: Weiter vorn hast du geschrieben, es gibt insgesamt ungefähr eine Million Objekte (Symbols und Subsymbols). Wie passen die denn in die 3 MB, die von der SPS geholt werden? Das sind ja gerade mal 3 Bytes pro Objekt. Also, irgendwas stimmt hier nicht ...



  • @Printee du hast rech da passt was nicht.
    Aber ich weiß noch nicht was.

    Wenn ich mir den Speicher im Visual Studio (Process Memory) und im Taskmanager (Arbeitsspeicher privater Arbeitsatz) vor und nach dem Laden der Informationen aus der SPS anschaue. Steigt dieser in letzten Test sogar nur um 1 MB.



  • Vergiss das, was dir irgendwelche Taskmanager erzählen. Vor allem, wenn du den Verdacht hast, dass mit deinem Speicher irgendwas durcheinandergeht.

    Wenn dein Programm die SPS-Daten ausliest, dann muss es doch aufs Byte genau feststellen können, wie viele das sind. Ich verstehe ehrlich gesagt nicht, was daran so schwierig ist.



  • Vergiss das, was dir irgendwelche Taskmanager erzählen. Vor allem, wenn du den Verdacht hast, dass mit deinem Speicher irgendwas durcheinandergeht.

    Ja natürlich aber für einen grobe Aussage tuts der Taskmanager.
    Und 1 MB ist wie du schon sagtest ziemlich wenig.

    Ich verstehe ehrlich gesagt nicht, was daran so schwierig ist.

    Wer hat behauptet das dies schwierig ist? Habe da nun nur nicht gleich so genau hingeschaut. Ist ja nicht das eigentliche Problem.

    Aber für dich ganz genau. Der Speicher steigt um genau: 682,38 KB



  • booster schrieb:

    Vergiss das, was dir irgendwelche Taskmanager erzählen. Vor allem, wenn du den Verdacht hast, dass mit deinem Speicher irgendwas durcheinandergeht.

    Ja natürlich aber für einen grobe Aussage tuts der Taskmanager.

    Wenn du verstanden hast wie das mit den Heaps funktioniert, und auf die richtige Spalte im Task-Manager guckst (die unter Windows 10 z.B. per Default gar nicht angezeigt wird), dann schon. Sonst nicht.



  • Irgendwie wird es solangsam echt unübersichtlich:

    Deine Software benötigt, abhängig von CString oder std::String 1,2 oder 2 GB Arbeitsspeicher.
    Aber das Delta von vor einlesen und danach mit den aufgebauten Datenstrukturen hast du nur ein Unterschied von unter einem MB.
    Ist das so richtig? Dann suchen wir offensichtlich an der falschen Stelle nach deinem Speicherverbrauch...

    Was anderes, du hast irgendwo geschrieben, das du eine Exception bekommst. Bekommst du die, nachdem du die zyklischen shared pointer aufgelöst hast immer noch?



  • @hustbear
    Bin unter Windows 7 und hier ist die Spalte Arbeitsspeicher (privater Arbeitssatz) eingeblendet!

    @SchlangenMensch

    Aber das Delta von vor einlesen und danach mit den aufgebauten Datenstrukturen hast du nur ein Unterschied von unter einem MB.
    Ist das so richtig? Dann suchen wir offensichtlich an der falschen Stelle nach deinem Speicherverbrauch...

    Nein der unterschied von unter einem MB ist vor und nach dem lesen der Daten aus der SPS. Das hat ja Pintee gefragt. Das ist noch bevor die Datenstruktur aufgebaut ist.

    Was anderes, du hast irgendwo geschrieben, das du eine Exception bekommst. Bekommst du die, nachdem du die zyklischen shared pointer aufgelöst hast immer noch?

    Ja die exception kommt immer kanpp an der unteren Grenze zu 2GB speicher. Dann komm bad allocation. Ich habe die nun mal mit rohzeigern und mit weak pointern gemacht. Habe nun mal für einen Test auch die ganzen Beziehungen untereinader mal weg gelassen. Bring nichts.



  • booster schrieb:

    Ich verstehe ehrlich gesagt nicht, was daran so schwierig ist.

    Wer hat behauptet das dies schwierig ist? Habe da nun nur nicht gleich so genau hingeschaut. Ist ja nicht das eigentliche Problem.

    Doch, genau das ist das Problem. Dass du nicht so genau hinschaust. Dein Programm verballert gigabyteweise Speicher für quasi nichts (immer schon) und du wunderst dich nicht darüber. Wieso auch - läuft ja alles prächtig.

    Aber für dich ganz genau. Der Speicher steigt um genau: 682,38 KB

    Offenbar ist das doch zu schwierig. Ich hatte nicht gefragt, um wieviel irgendwelche Anzeigen steigen, sondern wie groß der Rohdatenblock ist, den deine Software aus der SPS liest.

    Und wenn die 682KB tatsächlich die gelesene Blockgröße wären, dann wären das rund 0,7 Byte pro Symbol - es ist wirklich erstaunlich, dass du solche Zahlen stumpf abschreibst, ohne dich im Mindesten darüber zu wundern. Gehörst du etwas auch zu denen, die bei all dem Kilo-Mega-Giga schon lange den Überblick verloren haben?



  • Kannst du uns vlt mal den Code zeigen, wo die Datenstruktur aufgebaut wird? Bei deinen Beschreibungen kann ich mir aktuell nicht vorstellen, wo der Speicher verbaucht wird.
    Als mir das letzte mal Speicher dermaßen explodiert ist, musste ich einzelne Bilder aus Videos bearbeiten. Hast du irgendwelche komprimierte Daten die du nach einlesen noch extrahierst?



  • @Pintee
    Wieso schon wieder so agressiv.

    Doch, genau das ist das Problem. Dass du nicht so genau hinschaust. Dein Programm verballert gigabyteweise Speicher für quasi nichts (immer schon) und du wunderst dich nicht darüber. Wieso auch - läuft ja alles prächtig.

    Natürlich habe ich beim Speicherverbrauch genau hingeschaut. Meine Güte. Ich habe nicht genau hingeschaut bei dem was direkt aus der SPS kam. Hier lag ja nicht der Fehler. Muss ich gleich die ganze Welt in Frage stellen irgendwo muss ich ja anfangen.

    Ich habe das Programm übernommen und versuche zu optimieren.

    Und wenn die 682KB tatsächlich die gelesene Blockgröße wären, dann wären das rund 0,7 Byte pro Symbol - es ist wirklich erstaunlich, dass du solche Zahlen stumpf abschreibst, ohne dich im Mindesten darüber zu wundern. Gehörst du etwas auch zu denen, die bei all dem Kilo-Mega-Giga schon lange den Überblick verloren haben?

    ?? Was soll das nun. Natürlich wundere ich mich darüber habe ich ja geschrieben, das da irgendwas seltsam ist.
    Die Zahl habe ich vom Memory Profiler. Natürlich kann ich nun auch die Anzahl der Bytes aus dem Block angeben. Da sind 691408 Bytes.

    Du wolltest den genauen Speicher haben und regst dich danach auf wenn ich ihn hier reintippe.

    Was hast du vor dich durch deine Aggression hier profilieren?



  • booster schrieb:

    Da sind 691408 Bytes.

    Und da sollen allen Ernstes Informationen über eine Million Objekte drin enthalten sein? Inklusive Namen wie "MyDings.MyBums.MyDingelings"? Völlig ausgeschlossen.

    Was hast du vor dich durch deine Aggression hier profilieren?

    Ich habs nicht nötig, mich zu profilieren. Und du darfst ab jetzt alleine weiterwurschteln.



  • Und da sollen allen Ernstes Informationen über eine Million Objekte drin enthalten sein? Inklusive Namen wie "MyDings.MyBums.MyDingelings"? Völlig ausgeschlossen.
    

    Das versuche ich gerade heraus zu finden.

    Ich habs nicht nötig, mich zu profilieren.

    Nicht, ok dann liegts daran dass du einfach gerne ausrastest.
    Ich lasse mir gerne helfen, und akzeptiere auch Kritik. Aber ich muss mir auch nicht alles gefallen lassen.



  • Wenn es interessiert:

    Hier ist der Link wie die Informationen aus der SPS gelesen werden.

    https://infosys.beckhoff.com/index.php?content=../content/1031/tcadsnetref/4018095371.html&id=


Anmelden zum Antworten