Speicherverbrauch shared_ptr und normaler *



  • @TE
    Wenn dich jemand einen Ochsen nennt, dann hau ihm auf´s Maul.
    Wenn dich ein Zweiter einen Ochsen nennt, dann hau ihm auf´s Maul.
    Wenn dich ein Dritter einen Ochsen nennt wird´s Zeit einen Stall zu suchen.

    Merkst du nicht, dass du die Leute hier vergraulst? Seit 12 (!) Seiten ist immer noch nicht geklärt, was genau du eigentlich machst und wie deine Daten aussehen. Statt konkret zu liefern gibt´s ungenaue Beschreibungen und Salamitaktik, und wenn Anderen der Kragen platzt und einfach die Schnauze voll haben kommentierst du das mit Unverschämtheit und Profilierungssucht. So braun muss man erst mal sein...



  • Die 12 Seiten liegen vielleicht auch daran dass immer irgendwelche Seitenargumente daher kommen und ich alles mehrmals erklären muss.

    Ich habe immer Sachliche Argumente geliefert. Ich habe nie angegriffen. Immer erst dann als man mich beleidigt hat. Das nennt man Abwehr.

    Nur weil manchmal was falsch erklärt wurde muss man doch nicht ausfallend werden.


  • Mod

    booster schrieb:

    Sorry das war der falsche link.
    Hier ist der richtige:

    https://infosys.beckhoff.com/content/1031/tcsample_vc/html/tcadsdll_api_cpp_sample16.htm?id=3653485731247715096

    Grauenhaft. u.a. hat Der Author offenbar auch noch nie etwas von delete[] gehört. Dafür umso mehr virtual ohne Sinn und Verstand.

    Vermutlich solltest du nicht nach Speicher suchen, den deine Datenstruktur überflüssigerweise einnimmt, sondern nach Speicher, den du unterwegs verloren hast => alle new und delete durch geeignete Container ersetzen.



  • @camper
    ja das mit dem delete[] habe ich auch bemerkt. Dies habe ich bei mir im Code aber richtig gestellt. An dem liegt es nicht.

    Grauenhaft? Was meinst du genau ausser den falschen delete.



  • Gut wenn man sich das Beispiel runter lädt und die Klasse CAdsParseSymbols anschaut dann kann man grauenhaft sagen.



  • Das ist aber doch nicht der Code den du verwendest, oder? Zumindest finde ich keine Stelle, wo irgendwelche Maps befüllt werden oder ähnliches.



  • @Schlangenmensch

    Das ist der Code den ich verwende um die Informationen aus der SPS auszuelesen.
    Mit Hilfe dieser Informationen baue ich dann meine Flat- und TreeCollection auf.



  • Das ist der Code dazu

    void TcAdsSymbolInfoLoader::CreateCollection(const shared_ptr<AdsParseSymbols>& parseSymbols,
                                                 shared_ptr<TcAdsSymbolInfoCollection>& treeCollection,
                                                 shared_ptr<TcAdsSymbolInfoCollection>& flatCollection) const
    {
        if (!parseSymbols)
        {   
            const auto message = FTRANSLATE("Invalid argument '{1}'.", "parseSymbols");
            THROW_TRACEABLE_EXCEPTION(message);
        }
    
        treeCollection = make_shared<TcAdsSymbolInfoCollection>();
        flatCollection = make_shared<TcAdsSymbolInfoCollection>();
    
        AdsSymbolInfo	main;
        weak_ptr<TcAdsSymbolInfo> tclast;
    
        const auto symbolCount = parseSymbols->SymbolCount();
    
        for(unsigned int i=0; i < symbolCount; i++)
        {
            auto tcmain = make_shared<TcAdsSymbolInfo>();
    
            // next symbol für das vorherige setzen
            if( i != 0 )
            {
                tclast.lock()->_nextSymbol = tcmain;
            }
    
            parseSymbols->Symbol(i,main);
    
            const auto subsymbolCount = CreateSubSymbols(parseSymbols,main,tcmain);
    
            tcmain->AssignAdsSymbolInfo(main,subsymbolCount);
    
            flatCollection->Add(tcmain);
            treeCollection->Add(tcmain);
    
            // Symbol abspeichern für Zeiger auf letztes Element
            tclast = tcmain;
        }
    }
    
    int TcAdsSymbolInfoLoader::CreateSubSymbols(const shared_ptr<AdsParseSymbols>& parseSymbols,
                                                AdsSymbolInfo& parent,
                                                const shared_ptr<TcAdsSymbolInfo>& tcparent) const
    {   
        AdsSymbolInfo subinfo;
        weak_ptr<TcAdsSymbolInfo> tclast;
    
        const auto pDataType = parseSymbols->GetTypeByName(parent.type);
        const auto subSymbolCount = parseSymbols->SubSymbolCount(pDataType);
    
        for (unsigned int i = 0; i < subSymbolCount; i++)
        {
            auto tcsubinfo = make_shared<TcAdsSymbolInfo>();
            //auto tcsubinfo = new TcAdsSymbolInfo();
    
            // next symbol für das vorherige setzen
            if (i != 0)
                tclast.lock()->_nextSymbol = tcsubinfo;
            // erstes Subsymbol für parent setzen
            else
                tcparent->_firstSubSymbol = tcsubinfo;
    
            parseSymbols->SubSymbolInfo(parent, i, subinfo);
    
            // Symbol abspeichern für Zeiger auf letztes Element
            tclast = tcsubinfo;
    
            // Parent setzen
            tcsubinfo->_parent = tcparent;
    
            // SubSymbols rekursiv aufrufen
            const auto count = CreateSubSymbols(parseSymbols, subinfo, tcsubinfo);
    
            tcsubinfo->AssignAdsSymbolInfo(subinfo, count);
    
            _flatCollection->Add(tcsubinfo);
            tcparent->_subSymbols->Add(tcsubinfo);        
        }
    
        return subSymbolCount;
    }
    


  • Welchen Typ hat TcAdsSymbolInfo::_parent?



  • TcAdsSymbolInfo::_parent ist aktuell vom typ weak_ptr<TcAdsSymbolInfo>.

    TcAdsSymbolInfo ist eigentlich nur eine wrapper klasse um AdsSymbolInfo
    die ich dann in meinen Collections abspeichere

    class TcAdsSymbolInfo
    {
    
        /// Zeiger auf erstes Symbol
        weak_ptr<TcAdsSymbolInfo> _firstSubSymbol;
    
        /// Zeiger auf nächstes Symbol
        weak_ptr<TcAdsSymbolInfo> _nextSymbol;
    
        /// Zeiger auf Elternsymbol
        weak_ptr<TcAdsSymbolInfo> _parent;
    
        /// Zeiger auf Untersymbole
        shared_ptr<TcAdsSymbolInfoCollection> _subSymbols;
    
        /// Struktur mit Basisinformationen
        ITcAdsSymbol _baseInfos;
    
        void AssignAdsSymbolInfo(AdsSymbolInfo &info, const int subSymbolCount )
        {
            _baseInfos.comment          = info.comment;
            _baseInfos.datatype         = AdsDatatypeId::_from_integral(info.dataType);
            _baseInfos.indexGroup       = info.iGrp;
            _baseInfos.indexOffset	= info.iOffs;
            _baseInfos.name		= info.fullname;
            _baseInfos.shortName        = info.name;
            _baseInfos.size		= info.size;
            _baseInfos.type		= info.type;
            _baseInfos.subSymbolCount   = subSymbolCount;
        }
    }
    


  • Schau dir nochmal das Beispiel von weak_ptr hier an http://en.cppreference.com/w/cpp/memory/weak_ptr

    std::weak_ptr<int> gw;
    
    void observe()
    {
        std::cout << "use_count == " << gw.use_count() << ": ";
        if (auto spt = gw.lock()) { // Has to be copied into a shared_ptr before usage
    	std::cout << *spt << "\n";
        }
        else {
            std::cout << "gw is expired\n";
        }
    }
    
    int main()
    {
        {
            auto sp = std::make_shared<int>(42);
    	gw = sp;
    
    	observe();
        }
    
        observe();
    }
    

    Du läufst genau in die Falle, du erstellst mit make_shared in Zeile 59 einen shared ptr und weißt den in Zeile 64 oder 67 einem weak_ptr zu. Wenn der shared_ptr jetzt out of scope geht, ist der weak_ptr auch ungültig.



  • Ja ich erzeuge einen shared_ptr in Zeile 59 den ich dann in Zeile 83 und 84 meiner Collection zuweise. Das heißt die Collection ist dann der Besitzer des Objekts.

    der weak_ptr muss dann doch auch ungültig werden wenn das eigentliche objekt gelöscht wird. Das passiert ja erst wenn das Objekt aus der Collection raus fliegt.

    Oder nicht?



  • Oh, die Add() Funktion da hatte ich tatsächlich übersehen.
    Hängt natürlich von der Implementierung ab. Bei den Funktionen die du hier zeigst übergibst du immer eine Referenze auf einen shared_ptr. Das ist natürlich gut für die Performance, auf der anderen Seite verhinderst du damit, dass der reference count inkrementiert wird.
    Wie auch immer, dass kannst du recht einfach im Debugger oder mit einer Debug Ausgabe überprüfen und erklärt auch nicht, den von dir beschriebenen Speicherverbrauch deiner Anwendung.



  • Ja die Add Methode ist aber nicht const&

    void Add(shared_ptr<TcAdsSymbolInfo> symbolInfo)
    

  • Mod

    Wie verhalten sich das Programm+Log, wenn du

    static symbol_count = 0;
        PROCESS_MEMORY_COUNTERS mem_info;
        GetProcessMemoryInfo(GetCurrentProcess(), &mem_info, sizeof(mem_info));
        TRACE((to_string(++symbol_count) + " " + to_string(mem_info.WorkingSetSize)).c_str());
    

    vor dem return in CreateSubSymbols einfügst?
    Wieviel Speicher wird per Symbol im Schnitt benötigt?
    Ist der Speicherverbrauch pro Symbol (einigermaßen) konstant oder wächst er mit der Zeit?



  • @camper
    Habe das mit dem Visual Studio memoery profiler schon getestet.
    da hat jedes Symbol zwischen 0,6 - 3 K Byte
    das mal 1,4 Millionen Objekte kommt schon etwa hin mit den 2 GB.

    Aber ich teste das mit deinem Code schnipsel auch noch bevor wieder...



  • Ich meinte weniger den Aufruf von der Add Methode sonder eher das hinzufügen zur Map. Aber das ist ja im Moment auch egal. Wenn da was schief läuft, fliegt dir die Software zur Laufzeit irgendwann um die Ohren und reserviert nicht 2 GB Speicher.

    Hast du mal Valgrind, oder eine entsprechende alternative laufen lassen. Bei dem externen Code, den du gezeigt hast, bin ich mir nicht sicher, dass da alles sauber läuft.



  • Ja bei dem externen Code bin ich mir auch nicht sicher. Der sieht wirklich graunhaft aus.

    Aber ich weiß noch nicht ob der mein Speicher verbraucht.

    Und wieso der Code nur 600KB braucht um die die 1,4 Millionen Datensätze auszulesen ist auch noch nicht ganz klar.



  • booster schrieb:

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

    Ja. Das ist nicht die Spalte die du suchst. Die kann sich quasi beliebig ändern.

    Was du suchst ist "commit size". Ich weiss aber nicht wie die im Windows 7 Task Manager heisst. Und auch dann gibt's Pitfalls, nämlich dass der Heap freigegebenen Speicher nicht unbedingt ans System zurück gibt (bzw. das oft auch gar nicht kann), und dass AFAIK Programmcode sowie geladene DLLs mitgezählt werden.



  • @hustbear

    Würde mal sagen die commit size ist die "Zugesicherte Größe".


Anmelden zum Antworten