Speicher wird nicht mehr freigegeben ?!?!
-
Treb schrieb:
dann solltest du mal lernen die ausgaben von top und free zu interpretieren,
#free :
Mem: (total)2596496 (used)2280108 (free)316388
/+ buffers/cache: (used)724380 (free)1872116ich glaube die werte die bei der jeweiligen PID bei VIRT und RES stehen haben hier schon so manche aussagekraft in meinen augen. was unter used und free steht kann für solche messungen nicht direkt verwendet werden.
Treb schrieb:
das hat mit c++ nichts, aber auch wirklich garnichts zu tun, oder willst du linux noch vorschreiben, wann es cachen//buffern darf, und wann nicht?
nein tu ich doch gar nicht, aber warum verhalten sich dann IMMER div. designs gleich? warum habe ich bei design A am ende nur 1,5MB speicher verbraucht und bei design B 50MB speicherverbrauch obwohl IMMER alle objekte brav zerstört wurden? ich habe null speicherleichen und trotzdem sind bei diesem design 50MB verbraucht.
warum bleibt nun bei design B.1 wenn ich statt dem buffer der sonst immer im stack angelegt wurde und nun im heap am ende wieder nur noch 1,5MB über und nicht wie vorher 50MB und das obwohl bei beiden designs B und B.1 alle objekte zersötrt wurden.
-
taff schrieb:
... nur die frage ist, warum schaff ich eine lösung wo der speicher freigegeben wird
vector<Data> dataList;
und eine wo er nicht freigegeben wird?
vector<Data*> dataList;
Ganz einfach: Zufall !
Das ist genauso, wie es durchaus üblich ist, dass Lesezugriffe auf bereits freigegebenen Speicher noch erfolgreich sind (sprich: Das gewünschte Ergebnis liefern). Aber da bewegst Du Dich über die Zusagen des Standards hinaus und mit einem neu compilierten Kernel, anderen Startoption, .... klappt das vielleicht auch nicht mehr.taff schrieb:
...
Simon2 schrieb:
... ich würde sagen: Du verstehst die Welt von OS-Speichermanagement nicht.
Valgrind sagt Dir, dass Dein Programm alles richtig gemacht hat, das sollte Dir reichen.ähm das reicht leider eben nicht, weil dadurch habe ich einen zu hohen speicherverbrauch auf einem disklessserver, also so einfach ist die sache in meinen augen nicht, leider....
Dann solltest Dich aber "an Dein OS wenden". Das sind Probleme, die Du mit Standard-C++ nicht mehr lösen kannst.
Und dazu: Was ist denn "ein zu hoher Speicherverbrauch" ? Bekommt irgendein Programm keinen Speicher mehr ? Oder hättest Du einfach gerne noch ein paar MB frei ? ...
Gruß,
Simon2.
-
Simon2 schrieb:
Ganz einfach: Zufall !
Das ist genauso, wie es durchaus üblich ist, dass Lesezugriffe auf bereits freigegebenen Speicher noch erfolgreich sind (sprich: Das gewünschte Ergebnis liefern). Aber da bewegst Du Dich über die Zusagen des Standards hinaus und mit einem neu compilierten Kernel, anderen Startoption, .... klappt das vielleicht auch nicht mehr.aber der zufall ist für mich ein sehr schelchter zufall. ich habe das ganze nun auf 3 verschiedenen kernels probiert und überall das gleiche ergebnis bekommen. was mich jedoch am meisten wundert, dass ist die sache mit dem buffer den ich übergebe, damit ich den speicher fülle, dass sogar ein buffer der einmal angelegt wird und x-mal übergeben wird, das ganze beeinflussen kann ob am ende der speicher freigegeben wird oder nicht?! wie berichtet macht es einen unterschied aus ob man diesem im stack oder heap anlegt, obwohl dieser nur einmal angelegt wird?!
Simon2 schrieb:
Dann solltest Dich aber "an Dein OS wenden". Das sind Probleme, die Du mit Standard-C++ nicht mehr lösen kannst.
Und dazu: Was ist denn "ein zu hoher Speicherverbrauch" ? Bekommt irgendein Programm keinen Speicher mehr ? Oder hättest Du einfach gerne noch ein paar MB frei ? ...
Beides, weil wenn dann unsere techniker diskless-server planen, dann kommt es darauf an, wieviel speicher die dienste so verbrauchen und da eben bei so diskless servern nichts auf eine hdd gecached werden kann, hat man eben nur den speicher zuverfügung und somit soll das programm nur den speicher belegen den es auch wirklich braucht.
was mir auch noch aufgefallen ist, dass wenn ich mein testprogramm laufen lasse und ich starte einfach ein anderes programm welches nur den speicher frist und das ziel hat den speicher anzufüllen bis nichts mehr geht, dann wird der speicher von meinem testprogramm, welcher eigentlich nicht benötigt wird auch NICHT freigegeben, damit ein anderer dienst diesen verwenden könnte.
-
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.
-
Ups, war doppelt
-
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)
- dann habe ich mein testprogramm gestartet wo der speicher nicht mehr freigegeben wird am ende.
- 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.