Speicher wird nicht mehr freigegeben ?!?!



  • Tyrdal schrieb:

    Na dann ist dein Problem doch gelöst! Es wurde doch vorher schon im Thread beschrieben, daß das OS solange cached bis ein anderer Prozeß den Speicher braucht.

    wenn es so wäre, wäre es ja schön, leider wie berichtet:

    taff schrieb:

    dann wird der speicher von meinem testprogramm, welcher eigentlich nicht benötigt wird auch NICHT freigegeben, damit ein anderer dienst diesen verwenden könnte.



  • Doch, du hast doch selbst die valgrind-Ausgabe gepostet. Das was du als freien Speicher ansiehst ist aus OS-Sicht vergeudeter Speicher. Wenn ihn keine anderer Prozeß braucht wird er z.B. zwecks Performanceverbesserung für Caches genutzt. Wenn dann ein Prozeß trotzdem soviel Speicher braucht, daß der "freie" nicht ausreicht wird eben so ein Cache verkleinert o.ä.. Ergo, wenn du den Speicher in deinem Programm korrekt freigibst steht er anderen Programmen auch zu Verfügung.



  • aber laut top sind dann diesem dienst trotzdem noch immer 50MB zugewiesen und die werden dann trotzdem nicht abgegeben, wenn ein anderer dienst mehr speicher benötigen würde als was noch vorhanden ist.



  • Siehe mein Edit oben.



  • wie weiter oben berichtet, wollte ich das überprüfen ob dann dieser vergeudete speicher freigegeben wird. ich hab mir ein programm gebastelt, welches einfach nur speicher reserviert bis es nicht mehr geht. somit müssten eigentlich auch die 50mb welche korrekt freigegeben wurden, diesem speicher-fress-testprogramm zur verfügung gestellt werden. leider ist das nicht so. die 50mb werden diesem speicher-fress-testprogramm nicht zur verfügung gestellt.



  • Wie genau hast du das denn getestet? Gesamthauptspeicher - Kernel sollen allokiert werden, oder wie soll man das verstehen?



  • auf einem diskless server (also caching auf hdd nicht möglich)

    1. dann habe ich mein testprogramm gestartet wo der speicher nicht mehr freigegeben wird am ende.
    2. von meinem testprogramm eine andere version gebastelt, wo ich eben unendlich viele objekte anlege.

    ich konnte schön sehen wie der used mehr wurde und der free weniger 😃 bzw. auch der cached am ende weniger wurde, jedoch änderte sich nichts beim speicherverbrauch bei meinem programm, welches eigentlich den speicher freigegeben hat.



  • taff schrieb:

    wie weiter oben berichtet, wollte ich das überprüfen ob dann dieser vergeudete speicher freigegeben wird. ich hab mir ein programm gebastelt, welches einfach nur speicher reserviert bis es nicht mehr geht. somit müssten eigentlich auch die 50mb welche korrekt freigegeben wurden, diesem speicher-fress-testprogramm zur verfügung gestellt werden. leider ist das nicht so. die 50mb werden diesem speicher-fress-testprogramm nicht zur verfügung gestellt.

    Also wenn das wirklich so ist, dann ist irgendwas an Deinem OS oder Deiner C++-Runtimelib kaputt/schräg eingestellt.
    Was mich noch ein wenig interessiert:

    taff schrieb:

    meine neuen erkenntnnisse mit der swap-clear-lösung 😃
    ...
    2) vector wird mit new angelegt (heap) und nicht mit delete gelöscht, swap-clear funktioniert nicht!!!! (programm hat am ende 50MB) 👎
    ...

    Wie machst Du das genau ? Sowas in der Art ?

    vector<*int> v;
    for(i=0; i<=max; ++i) v.push_back(new int);
    

    ??

    Dann wäre es vollkommen klar, weil vector<T*> kein delete aufruft => Ergo: Selbstgebasteltes Speicherleck.
    Der "Swap-clear-Trick" ist für eine andere Situation gedacht. Er ist nicht dazu da, deletes zu ersetzen.

    Übrigens: Ich würde unter "... vector mit new angelegt ..." sowas verstehen:

    vector<int> *v = new vector<int>;
    for(i=0; i<=max; ++i) v->push_back(1);
    

    Aber auch hier braucht's ein abschließendes delete....

    EDIT: Aber beides hätte valgrind bestimmt gefunden !!

    Gruß,

    Simon2.



  • muss gestehen, dass ich den 2. punkt von damals nicht mehr so hinbekomme mit diesem fehler, liegen doch schon zu viele versionen dazwischen 😡 , jedoch weiß ich hier nun wie ich mir abhelfen kann, wenn das vector-daten-element im stack angelegt wird.

    anders sieht es aus, wenn dies im heap liegt, man kann auch einen smart_ptr verwenden, gleiches problem:

    #define LIST_COUNT 5
    #define BUFFER_SIZE 1024
    #define BUFFER_ADDS 10000
    
    class Data 
    {
    	public:
    		string name;
    
    	public:
    		Data() {}
    		~Data() {}
    		void Set(const char* _name) {name = _name;}
    };
    
    class DataListPointer
    {
    	private:
    		 vector<Data*> dataList;	
    
    	public:
    		DataListPointer() {}
    		virtual ~DataListPointer() { }
    
    		void Clear()
    		{
    			cout << "DataListPointer::Clear()" << endl;
    			for(uint i=0; i< dataList.size(); i++)
    			{
    				delete dataList.at(i);
    				dataList.at(i) = NULL;
    			}
    			dataList.clear();
    			vector<Data*>().swap(dataList); // kann man aufrufen oder weglassen, hat am ende keinen einfluss 
    		}
    
    		void Add(const char *_name)
    		{
    			Data *dataobj(new Data());
    
    			// Name setzen ----
    			if (_name) dataobj->Set(_name);
    
    			// Element in Liste hinzfügen
    			dataList.push_back (dataobj);
    		}
    };
    
    int main ()
    {
    	char buffer[BUFFER_SIZE+1];
    	memset(buffer, 'A', BUFFER_SIZE);
    	buffer[BUFFER_SIZE] = '\0';
    
    	DataListPointer *datalist[LIST_COUNT];
    
    	for(int idx=0; idx<LIST_COUNT; idx++)
    	{
    		datalist[idx] = new DataListPointer();
    		for(int i=0; i<BUFFER_ADDS; i++)
    			datalist[idx]->Add(buffer);
    	}
    
    	for(int idx=0; idx<LIST_COUNT; idx++)
    	{
    		datalist[idx]->Clear();
    		delete datalist[idx];
    		datalist[idx] = NULL;
    	}
    
    	while(1)
    		sleep(1);
    
    }
    

    lege ich aber den BUFFER im heap an:

    char *buffer = new char[BUFFER_SIZE+1];
    

    dann wird komischer weise beim delete des buffers wieder alles freigegeben, also auch die uminösen 50MB.

    verwende ich für den buffer einen stl-string

    string buffer;
    buffer.append(BUFFER_SIZE+1, 'A');
    

    werden am ende auch die 50MB nicht freigegeben!

    ich wäre froh, wenn das obige beispiel wer testhalber auf seiner maschine laufen lassen könnte, weil ich komm mir schon vor als würde ich sachen erzählen die mir niemand glaubt 😞 🙄 BITTE - DANKE



  • Wenn ich dein Programm ausführe, belegt es während der while-Schleife 1,144 KB laut TaskManager unter Windows XP.



  • jepp da hast du recht. unter linux sieht das leider anders aus und genau um das geht es mir 😞



  • Also, ich weiß nicht was du noch von uns willst? Es ist eine OS-Eigenheit. Punkt! Da kann doch C++ nichts für.

    Bei FreeBSD ist es sogar noch extremer: da kann gar kein Programm laufen, und trotzdem kann sich FreeBSD 900 MB von 1000 MB RAM reservieren. Und das ohne, das ein dann startendes Programm das 500 MB braucht, an Speichermangel leiden muß. Weil es einfach was von den 900 MB wieder abbekommt. Aber da kann keine Anwendung etwas dran ändern, was im "Taskmanager" drin drin steht.

    Und selbst wenn C++ daran "schuld" sein sollte, dann kann es auch von der C/C++-Runtime (CRT) des Compilers abhängen. Z.B. ist bei MSVC2008 eine andere/neue CRT dabei, die sich im Verhalten anders verhalten kann, als die CRT von MSVC2005. Da kann man als Nutzer der CRT nichts dran machen, wenn sich das im Taskmanager anders auswirkt, nur weil ich von CRT 2005 auf CRT 2008 umsteige.

    Nichts anderes wird sein, wenn du Linux XYZ mit Compiler XYZ benutzt.

    Was sagt denn dein Memoryleak-Tool dazu? Sagt es, das du Speicher nicht frei gegeben hast?



  • mir ist klar, dass es abhängigkeiten von compiler, kernel, etc. gibt, jedoch verstehe ich das verhalten nicht:
    aber warum wird in div. fällen (vector-datenelement wird im stack angelegt oder die variable die ich zum füllen des vectors übergebe -> "buffer" wird im heap angelegt) der speicher freigegeben und in anderen fällen nicht?
    gerade die sache mit der übergabe variable die tausendemale übergeben wird macht den unterschied aus, ob dann der speicher freigegeben wird am ende oder nicht?
    warum wird dann der speicher nicht freigegeben, wenn andere dienste den speicher brauchen würden?

    valgrind sagt, dass alle elemente die angelegt wurden freigegeben wurden und trotzdem habe ich noch bei meiner pid im top in der RES spalte 50mb stehen.

    ich kann mir einfach nicht vorstellen, dass jedem c++ entwickler der speicherverbrauch egal ist oder sich damit abfindet?



  • Du begreifst anscheinend immer noch nicht, was wir dir sagen wollen - was das System mit dem Speicher macht, den es von dir zurückgegeben bekommt, liegt in seiner eigenen Verantwortung - darauf hast du keinen Einfluß (und da hat sich der Entwickler des Compilers und Betriebssystems schon genug Gedanken gemacht, wie er am effektivsten mit seinem Speicher umgehen kann). Du mußt dich nur um den Speicher kümmern, den du selber angefordert hast - und sicherstellen, daß dieser vor Programmende wieder freigegeben wird*.

    (btw, bei den STL-Containern liegt noch der Allokator zwischen dir und der Speicherverwaltung - und der kann auch entscheiden, Teile des freigegebenen Speichers auf Vorrat zu halten, bis sie (wieder) benötigt werden)

    * eigentlich holen sich nach Programmende die meisten Systeme den Speicher wieder, den du angefordert hast - allerdings ohne sich um Destruktoren und ähnliches zu kümmern.



  • taff schrieb:

    aber warum wird in div. fällen (vector-datenelement wird im stack angelegt oder die variable die ich zum füllen des vectors übergebe -> "buffer" wird im heap angelegt) der speicher freigegeben und in anderen fällen nicht?

    Wenn du im Heap reservierst, ist das was anderes als im Stack. Und natürlich können die beiden sich anders verhalten. SOLLEN sie auch! Wenn sie es nicht tun würden, bräuchte man nicht zwei verschiedene. Das ist ja der Witz an der ganzen Sache.

    taff schrieb:

    gerade die sache mit der übergabe variable die tausendemale übergeben wird macht den unterschied aus, ob dann der speicher freigegeben wird am ende oder nicht?
    warum wird dann der speicher nicht freigegeben, wenn andere dienste den speicher brauchen würden?

    Von wen redest du? Von DEINER Speicherfreigabe in DEINEM Programm? Oder von der der CRT und OS? Werde doch mal konkreter! Und meine Frage von oben, bzgl. des Memoryleak-Tools, hast du nicht beantwortet! Mach das bitte erstmal! ⚠

    taff schrieb:

    ich kann mir einfach nicht vorstellen, dass jedem c++ entwickler der speicherverbrauch egal ist oder sich damit abfindet?

    Ja, mir ist der Speicherverbrauch egal, wenn ich diesen selber nicht beeinflussen kann. Das was ich beeinflussen kann, kann ich notfalls (wenn es mir nicht passt) ändern. Alles andere, ist mir tatsächlich egal. Und soll mir auch egal sein, weil sonst kann ich auch gleich anfangen, und mein eigenes OS programmieren. Was ich aber nicht will, weil sich andere schon gedanken darüber gemacht haben... nämlich MS, Linux, FreeBSD usw.



  • @cstoll
    das ganze wäre für mich kein problem, wenn dann der speicher auch für andere programme freigegeben werden würde, leider musste ich bei einem test feststellen, dass dies nicht so ist 😞

    das allokator "problem" sollte eigentlich mit dem "swap-trick" behoben sein.

    das nach dem programm-ende der speicher freigegeben wird hilft mir in diesem fall nichts, wenn das programm mehrere monate durchlaufen sollte.

    wie schon berichtet, hängt zb. von dieser variable viel ab:

    char buffer[BUFFER_SIZE+1];
    

    diese varialbe wird 50.000 übergeben und dann in einen stl-string des vector-daten-elementes kopiert. lege ich diese buffer-variable im heap an und mache das delete nachdem ich alle vector-elemente zerstört habe, dann wird auch der belegte speicher vom vector freigegeben. was haben 1024bytes die 50.000 mal übergeben wurden mit dem nicht freigegeben speicher zu tun?



  • Artchi schrieb:

    Wenn du im Heap reservierst, ist das was anderes als im Stack. Und natürlich können die beiden sich anders verhalten. SOLLEN sie auch! Wenn sie es nicht tun würden, bräuchte man nicht zwei verschiedene. Das ist ja der Witz an der ganzen Sache.

    nur sollten sich nicht 1024byte einer variable die einmal angelegt wurden nicht auf andere 50mb im speicher auswirken, oder?

    Artchi schrieb:

    Von wen redest du? Von DEINER Speicherfreigabe in DEINEM Programm? Oder von der der CRT und OS? Werde doch mal konkreter! Und meine Frage von oben, bzgl. des Memoryleak-Tools, hast du nicht beantwortet! Mach das bitte erstmal! ⚠ .

    ähm valgrind ist ein memoryleak tool .... ev hast du das überlesen! und wie gesagt hier liefert mir valgrind das alle angelegten objekte zerstört und freigegeben wurden und trotzdem bleiben im top bei meiner pid in der RES spalte 50mb über.

    Artchi schrieb:

    Ja, mir ist der Speicherverbrauch egal, wenn ich diesen selber nicht beeinflussen kann. Das was ich beeinflussen kann, kann ich notfalls (wenn es mir nicht passt) ändern. Alles andere, ist mir tatsächlich egal. Und soll mir auch egal sein, weil sonst kann ich auch gleich anfangen, und mein eigenes OS programmieren. Was ich aber nicht will, weil sich andere schon gedanken darüber gemacht haben... nämlich MS, Linux, FreeBSD usw.

    leider ist mir der speicherverbrauch nciht egal, weil wenn ein dienst zb. 500mb auf diese art und weise auf einer diskless maschine verbraucht und dann 5000 kunden dadurch mehr ram brauchen, dann ist das in meinen augen schon ein problem



  • taff schrieb:

    nur sollten sich nicht 1024byte einer variable die einmal angelegt wurden nicht auf andere 50mb im speicher auswirken, oder?

    Ob sie es sollten, ist eine Design-Frage. Ich sage mal so: ich erwarte sowas nicht in meiner aktuellen Umgebung. Aber ich sage, das es passieren kann, wenn es der Allokator, CRT oder OS so wollen. Und das ist der entscheidende Punkt, wo du dich von mir unterscheidest. Du willst es nicht wahrhaben und nicht akzeptieren. Ich würde darüber nicht erfreut sein, könnte es akzeptieren, wenn mir der Designer des Allokator, CRT oder OS es mir erklärt, weil er es so wollte und toll findet.

    Wenn ich damit nicht leben kann, muß ich handeln! Und zwar den "Übeltäter" ausfindig machen, und ihn auswechseln!

    taff schrieb:

    ähm valgrind ist ein memoryleak tool .... ev hast du das überlesen! und wie gesagt hier liefert mir valgrind das alle angelegten objekte zerstört und freigegeben wurden und trotzdem bleiben im top bei meiner pid in der RES spalte 50mb über.

    Sorry, bin nicht Linux-bewandert. Muß bei mir untergegangen sein. 😉 Gut, aber dieses Memoryleakdetector-Tool namens valgrind sagt dir: "In deinem C++-Programm, das DU geschrieben hast, hast du alles formal korrekt gemacht, was Resourcenfreigabe betrifft."
    So, das sagt mir, das du somit dieses Topic in diesem Forum abschliessen kannst. Weil ISO-C++-mäßig gibt es keine Fragen mehr.

    taff schrieb:

    leider ist mir der speicherverbrauch nciht egal, weil wenn ein dienst zb. 500mb auf diese art und weise auf einer diskless maschine verbraucht und dann 5000 kunden dadurch mehr ram brauchen, dann ist das in meinen augen schon ein problem

    Yo, das glaube ich dir gerne. Nur mußt du herausfinden, warum das so ist. Aber du suchst an der falschen Stelle. Das sagt dir auch Valgrind, weshalb ich nach dessen Ergebnis gefragt habe.

    Ich würde jetzt mal folgendes machen: den Support für deine CRT und dein OS fragen, wie die Speicherallokierung und Freigabe funktioniert. (wobei ich erst bei der CRT anfangen würde!) Nur die können dir die Frage beantworten, was im Hintergrund passiert und warum das so extrem ist. Und ich wette, du wirst zu dem Ergebnis kommen, das du eine Komponente austauschen werden mußt. Im einfachsten Fall nur den Allokator. Evtl. kannst du ihn auch selber schreiben. Oder eine andere CRT oder Compiler benutzen, die eher für Diskless-HW designed und implementiert ist.

    Im schlimmsten Fall das OS auswechseln! (Und dann müsstest du deinen Kunden halt ein bestimmtes OS vorschreiben, was für Diskless-Rechner geeignet ist.)



  • Wenn du Angst hast, dein Programm könnte durch das "tausendemale übergeben" von großen Objekten zu viel Speicher fressen, dann übergib deine Riesen-Objekte doch nicht so oft - neben dem Speicherplatz kostet das nämlich auch Laufzeit. (zur Not kannst du auch (const)Referenzen übergeben ;))

    taff schrieb:

    das allokator "problem" sollte eigentlich mit dem "swap-trick" behoben sein.

    Nein, ist es vermutlich nicht - mit dem Swap-Trick gibst du nur den ungenutzten Speicherplatz des vectors an den Allocator zurück, was der damit macht, ist seine Angelegenheit (normalerweise sollte der diesen Speicher entweder ans System zurückgeben oder dem nächsten vector zuschanzen, der ihn benötigt).



  • Artchi schrieb:

    Ob sie es sollten, ist eine Design-Frage. Ich sage mal so: ich erwarte sowas nicht in meiner aktuellen Umgebung. Aber ich sage, das es passieren kann, wenn es der Allokator, CRT oder OS so wollen. Und das ist der entscheidende Punkt, wo du dich von mir unterscheidest. Du willst es nicht wahrhaben und nicht akzeptieren. Ich würde darüber nicht erfreut sein, könnte es akzeptieren, wenn mir der Designer des Allokator, CRT oder OS es mir erklärt, weil er es so wollte und toll findet.

    ich will es nicht wahrhaben, wenn im falle der speichernot dieser speicher nicht freigegeben wird, dass es nicht sofort freigegeben wird, darüber bin ich nicht glücklich.

    Artchi schrieb:

    Wenn ich damit nicht leben kann, muß ich handeln! Und zwar den "Übeltäter" ausfindig machen, und ihn auswechseln!

    wird mir leider nicht übrigbleiben, da ich auch schon mir ganz normale verkettete listen und strings gebastelt habe, damit ich keine abhängigkeiten von der stl habe - gleicher effekt.

    Artchi schrieb:

    Im schlimmsten Fall das OS auswechseln! (Und dann müsstest du deinen Kunden halt ein bestimmtes OS vorschreiben, was für Diskless-Rechner geeignet ist.)

    das wird wohl der schwierigste teil werden, wenn das ganze auf jedem 0815 suse und konsorten laufen soll

    DANKE jedenfalls für deine hilfe und dein verständnis! 👍

    CStoll schrieb:

    Wenn du Angst hast, dein Programm könnte durch das "tausendemale übergeben" von großen Objekten zu viel Speicher fressen, dann übergib deine Riesen-Objekte doch nicht so oft - neben dem Speicherplatz kostet das nämlich auch Laufzeit. (zur Not kannst du auch (const)Referenzen übergeben )

    nein die angst habe ich nicht, da ich ja nur den pointer übergebe auf dieses char-array und wenn mein vector-element im stack angelegt wird dann übergebe ich auch 50.000 mal 1024 bytes und ich habe am ende nicht das problem, jedoch wenn ich das vector-element im heap anlege, dann ist es auch entscheidend wo ich diese buffer-varialbe anlege. 🙄

    CStoll schrieb:

    Nein, ist es vermutlich nicht - mit dem Swap-Trick gibst du nur den ungenutzten Speicherplatz des vectors an den Allocator zurück, was der damit macht, ist seine Angelegenheit (normalerweise sollte der diesen Speicher entweder ans System zurückgeben oder dem nächsten vector zuschanzen, der ihn benötigt).

    wie gerade oben beschrieben bei einer selbstgebauten liste usw. genau das gleiche problem.


Anmelden zum Antworten