Speicher wird nicht freigegeben
-
hallo, ich habe ein ziemlich ernsthaftes problem mit meinem programm. ich lege während der laufzeit ca 1 mio objekte auf dem heap an. diese objekte werden erzeugt, indem eine xml datei geparset wird und jedes tag als objekt angelegt wird. wenn ich den taskmanager öffne verbraucht mein programm fast 570000k speicher. soweit alles kein problem wenn man einen relativ neuen rechner hat. wenn ich aber nach allen berechnungen die objekte wieder löschen bzw den speicher freigeben will hängt sich meine gui/programm auf und im taskmanager wird der speicherverbrauch auch nicht weniger, was ja eigentlich der fall sein sollte wenn ich diesen wieder freigebe. der parser wird während der laufzeit angelegt und nach allen aufgaben wieder gelöscht. folglich wird der destruktor aufgerufen:
OSM_Parser::~OSM_Parser() { delete reader; delete file; qDebug() << "Destruktor"; if(!relationContainer.isEmpty()) { qDebug() << "relationContainer"; QHashIterator<QString, OSM_Relation*> i(relationContainer); while (i.hasNext()) { //qDebug() << "delete relation"; i.next(); OSM_Relation *relation = i.value(); delete relation; } relationContainer.clear(); } if(!wayContainer.isEmpty()) { //qDebug() << "wayContainer"; QHashIterator<QString, OSM_Way*> x(wayContainer); while (x.hasNext()) { //qDebug() << "delete way"; x.next(); OSM_Way *way = x.value(); delete way; } wayContainer.clear(); } if(!nodeContainer.isEmpty()) { //qDebug() << "nodeContainer"; QHashIterator<QString, OSM_Node*> k(nodeContainer); while (k.hasNext()) { //qDebug() << "delete node"; k.next(); OSM_Node *node = k.value(); delete node; } nodeContainer.clear(); } }was mache ich falsch bzw kennt jmd ne alternative ?
-
Kanaka82 schrieb:
freigeben will hängt sich meine gui/programm auf
Wo hängt sich das programm auf? (Debugger)
gibt es eine Fehlermeldung?ohne genaue Infos müsste man raten. Dan würde ich auf eine Endlosschleiffe in einem While tippen.
-
nun, bei kleineren xml dateien die nicht so viele objekte erzeugen funktioniert es soweit. hab mal testweise nur eine hand voll objekte erzeugen lassen und da läuft alles durch. ich vermute das er einfach mit den riesigen datenmengen nicht klar kommt. anders kann ich mir das nicht erklären.
-
Nur so nebenbei: Was der Taskmanager anzeigt ist nur bedingt abhängig von der Freigabe von Speicher. Denn was der Taskmanager zeigt ist wieviel Speicher er dem Prozess zuschreibt, nicht wie viel dieser tatsächlich noch/schon verbraucht.
-
Zeig mal die Definition der Klasse OSM_Parser
-
Dass Du im Destruktor so oft "delete" drin stehen hast, ist schonmal unschön. Es lässt sich bestimmt vermeiden. Ich denke, RAII ist noch nicht richtig von Dir verstanden worden.
-
ich bin mit meinem latein wirklich am ende. ich habe nun die ganze nacht damit verbracht den fehler zu finden, konnte das problem aber nur ansatzweise einkreisen. bei kleineren xml dateien bzw wenn man nur ein paar tausend objekte erzeugt läuft das programm einwandfrei. im process explorer kann man klar erkennen das sich der speicherverbrauch zwar erhöht, wenn man jedoch die objekte wieder freigibt pendelt es sich wieder ein. wenn man aber die objektanzahl auf 1 mio erhöht, blockt die GUI bei dem punkt wo alle angelegten objekte wieder freigegeben werden sollen. das programm scheint dann eingefroren zu sein, jedoch muss man nur sehr lange warten bis das programm erfolgreich endet. habe extra für die dauer der objekterzeugung und deren verwendung einen eigenen thread implementiert. der debugger läuft auch durch alle freigaben die ich gesetzt habe. ich habe nochmal einen teil des codes gepostet in der hoffnung das ihr vllt mehr erkennt. jedes im parser erzeugte objekte habe ich mit new erzeugt, weil ich dachte das der heap besser geeignet ist für solche datenmengen. könnte das der fehler sein ?
#ifndef OSM_PARSER_H #define OSM_PARSER_H #include <QHash> #include <QXmlStreamReader> #include <QFile> #include <QDebug> #include <QStringList> #include "osm_node.h" #include "osm_way.h" #include "osm_relation.h" class OSM_Parser : public QObject { Q_OBJECT public: OSM_Parser(); ~OSM_Parser(); void clear(); bool readFile(const QString fileName, QList<QString> *tagList); QHash<QString*, OSM_Node*>* getNodeContainer(); QHash<QString*, OSM_Way*>* getWayContainer(); QHash<QString*, OSM_Relation*>* getRelationContainer(); QHash<QString*, OSM_Node*>* getConvertableNodes(); QHash<QString*, OSM_Way*>* getConvertableWays(); QHash<QString*, OSM_Relation*>* getConvertableRelations(); int getNumberOfTags(); QString getBoundBox(); signals: void filePosChanged(long filePos, long fileSize); public slots: void stopParser(); private: void readOSMElement(); void readBoundElement(); void readNodeElement(); void readWayElement(); void readNdElement(OSM_Way *way); void readRelationElement(); void readMemberElement(OSM_Relation *relation); void readTagElement(OSM_Node *node, OSM_Way *way, OSM_Relation *rel); void skipUnknownElement(); QFile *file; QXmlStreamReader *reader; bool stop; OSM_Node *node; OSM_Way *way; OSM_Relation *relation; QString boundBox; QHash<QString*, OSM_Node*> nodeContainer; QHash<QString*, OSM_Way*> wayContainer; QHash<QString*, OSM_Relation*> relationContainer; QHash<QString*, OSM_Node*> convertableNodes; QHash<QString*, OSM_Way*> convertableWays; QHash<QString*, OSM_Relation*> convertableRelations; QList<QString> *parseableTags; int numberOfTags; }; #include "osm_parser.h" OSM_Parser::OSM_Parser() { node = 0; way = 0; relation = 0; reader = new QXmlStreamReader(); file = new QFile(); numberOfTags = 0; parseableTags = 0; } OSM_Parser::~OSM_Parser() { delete reader; delete file; qDebug() << "Destruktor"; } void OSM_Parser::clear() { if(!relationContainer.isEmpty()) { qDebug() << "relationContainer"; QHashIterator<QString*, OSM_Relation*> i(relationContainer); while (i.hasNext()) { //qDebug() << "delete relation"; i.next(); delete i.key(); delete i.value(); } relationContainer.clear(); } if(!wayContainer.isEmpty()) { //qDebug() << "wayContainer"; QHashIterator<QString*, OSM_Way*> x(wayContainer); while (x.hasNext()) { //qDebug() << "delete way"; x.next(); delete x.key(); delete x.value(); } wayContainer.clear(); } if(!nodeContainer.isEmpty()) { //qDebug() << "nodeContainer"; QHashIterator<QString*, OSM_Node*> k(nodeContainer); while (k.hasNext()) { //qDebug() << "delete node"; k.next(); delete k.key(); delete k.value(); } nodeContainer.clear(); } if(!convertableRelations.isEmpty()) { qDebug() << "relationContainer"; QHashIterator<QString*, OSM_Relation*> c(convertableRelations); while (c.hasNext()) { //qDebug() << "delete relation"; c.next(); delete c.key(); } convertableRelations.clear(); } if(!convertableWays.isEmpty()) { //qDebug() << "wayContainer"; QHashIterator<QString*, OSM_Way*> b(convertableWays); while (b.hasNext()) { //qDebug() << "delete way"; b.next(); delete b.key(); } convertableWays.clear(); } if(!convertableNodes.isEmpty()) { //qDebug() << "nodeContainer"; QHashIterator<QString*, OSM_Node*> a(convertableNodes); while (a.hasNext()) { //qDebug() << "delete node"; a.next(); delete a.key(); } convertableNodes.clear(); } } bool OSM_Parser::readFile(const QString fileName, QList<QString> *tagList) { file->setFileName(fileName); stop = false; parseableTags = tagList; // qDebug() << parseableTags->count(); if (file->open(QFile::ReadOnly | QFile::Text)) { emit filePosChanged(file->pos(),file->size()); // XML Reader wird eine Datei zugewiesen reader->setDevice(file); reader->readNext(); while (!reader->atEnd()) { if (reader->isStartElement()) { if (reader->name() == "osm") { readOSMElement(); if(stop) { file->close(); return false; } } else { reader->raiseError(QObject::tr("Not a osm file")); } } else { reader->readNext(); } } file->close(); if (reader->hasError()) { // qDebug() << QString("Error: Failed to parse file "); // << qPrintable(fileName) << ": "<< qPrintable(reader->errorString()) << std::endl; return false; } else if (file->error() != QFile::NoError) { // qDebug() << QString("Error: Cannot read file "); //<< qPrintable(fileName) << ": " << qPrintable(file.errorString()) << std::endl; return false; } } else { // qDebug() << "Cannot Open File"; return false; } return true; } void OSM_Parser::readOSMElement() { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); if(reader->attributes().hasAttribute("xapi:uri")) { // qDebug() << boundBox; boundBox = reader->attributes().value("xapi:uri").toString(); QStringList list = boundBox.split("="); QStringList list2 = list.at(1).split(","); boundBox = list2.at(1) + "," + list2.at(0) + "," + list2.at(3) + "," + list2.at(2); } // qDebug() << "OSM"; reader->readNext(); while (!reader->atEnd()) { if (reader->isEndElement()) { reader->readNext(); break; } if (reader->isStartElement()) { if (reader->name() == "bound") { readBoundElement(); if(stop) { return; } } else if (reader->name() == "node") { readNodeElement(); if(stop) { return; } } else if (reader->name() == "way") { readWayElement(); if(stop) { return; } } else if (reader->name() == "relation") { readRelationElement(); if(stop) { return; } } else { skipUnknownElement(); if(stop) { return; } } } else { reader->readNext(); } } } void OSM_Parser::readBoundElement() { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Bound"; // qDebug() << reader->attributes().value("box").toString(); boundBox = reader->attributes().value("box").toString(); reader->readNext(); if (reader->isEndElement()) { reader->readNext(); } } void OSM_Parser::readNodeElement() { // qDebug() << "Node"; // qDebug() << reader->attributes().value("id").toString(); if(stop) { return; } emit filePosChanged(file->pos(),file->size()); node = new OSM_Node(new QString(reader->attributes().value("lat").toString()),new QString(reader->attributes().value("lon").toString())); nodeContainer.insert(new QString(reader->attributes().value("id").toString()),node); reader->readNext(); while (!reader->atEnd()) { if (reader->isEndElement()) { reader->readNext(); break; } if (reader->isStartElement()) { if (reader->name() == "tag" && parseableTags->contains(reader->attributes().value("v").toString())) { readTagElement(node,0,0); if(stop) { return; } } else { skipUnknownElement(); if(stop) { return; } } } else { reader->readNext(); } } } void OSM_Parser::readWayElement() { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Way"; // qDebug() << reader->attributes().value("id").toString(); way = new OSM_Way(); wayContainer.insert(new QString(reader->attributes().value("id").toString()),way); reader->readNext(); while (!reader->atEnd()) { if (reader->isEndElement()) { reader->readNext(); break; } if (reader->isStartElement()) { if (reader->name() == "nd") { readNdElement(way); if(stop) { return; } } else if (reader->name() == "tag" && parseableTags->contains(reader->attributes().value("v").toString())) { readTagElement(0,way,0); if(stop) { return; } } else { skipUnknownElement(); if(stop) { return; } } } else { reader->readNext(); } } } void OSM_Parser::readNdElement(OSM_Way *way) { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Nd"; // qDebug() << reader->attributes().value("ref").toString(); way->fillReferenceList(new QString(reader->attributes().value("ref").toString())); reader->readNext(); if (reader->isEndElement()) { reader->readNext(); } } void OSM_Parser::readRelationElement() { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Relation"; // qDebug() << reader->attributes().value("id").toString(); relation = new OSM_Relation(); relationContainer.insert(new QString(reader->attributes().value("id").toString()),relation); reader->readNext(); while (!reader->atEnd()) { if (reader->isEndElement()) { reader->readNext(); break; } if (reader->isStartElement()) { if (reader->name() == "member") { readMemberElement(relation); if(stop) { return; } } else if (reader->name() == "tag" && reader->attributes().value("v").toString() == "multipolygon") { readTagElement(0,0,relation); if(stop) { return; } } else { skipUnknownElement(); if(stop) { return; } } } else { reader->readNext(); } } } void OSM_Parser::readMemberElement(OSM_Relation *rel) { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Member"; // qDebug() << reader->attributes().value("type").toString(); // qDebug() << reader->attributes().value("ref").toString(); if(reader->attributes().value("type").toString() == "way" && reader->attributes().value("role").toString() == "inner") { rel->fillWayList(new QString(reader->attributes().value("ref").toString())); } reader->readNext(); if (reader->isEndElement()) { reader->readNext(); } } void OSM_Parser::readTagElement(OSM_Node *node, OSM_Way *way, OSM_Relation *rel) { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Tag"; // qDebug() << reader->attributes().value("k").toString(); numberOfTags++; if(node != 0) { convertableNodes.insertMulti(new QString(reader->attributes().value("v").toString()),node); } if(way != 0) { convertableWays.insertMulti(new QString(reader->attributes().value("v").toString()),way); } if(rel != 0) { convertableRelations.insertMulti(new QString(reader->attributes().value("v").toString()),rel); } reader->readNext(); if (reader->isEndElement()) { reader->readNext(); } } void OSM_Parser::skipUnknownElement() { if(stop) { return; } emit filePosChanged(file->pos(),file->size()); // qDebug() << "Skip"; reader->readNext(); while (!reader->atEnd()) { if (reader->isEndElement()) { reader->readNext(); break; } if (reader->isStartElement()) { skipUnknownElement(); if(stop) { return; } } else { reader->readNext(); } } } QHash<QString*, OSM_Node*>* OSM_Parser::getNodeContainer() { return &nodeContainer; } QHash<QString*, OSM_Way*>* OSM_Parser::getWayContainer() { return &wayContainer; } QHash<QString*, OSM_Relation*>* OSM_Parser::getRelationContainer() { return &relationContainer; } QHash<QString*, OSM_Node*>* OSM_Parser::getConvertableNodes() { return &convertableNodes; } QHash<QString*, OSM_Way*>* OSM_Parser::getConvertableWays() { return &convertableWays; } QHash<QString*, OSM_Relation*>* OSM_Parser::getConvertableRelations() { return &convertableRelations; } int OSM_Parser::getNumberOfTags() { return numberOfTags; } QString OSM_Parser::getBoundBox() { return boundBox; } void OSM_Parser::stopParser() { stop = true; // qDebug() << stop; } #endif // OSM_PARSER_H #ifndef OSM_NODE_H #define OSM_NODE_H #include <QString> class OSM_Node { public: OSM_Node(QString *lat, QString *lon); OSM_Node::~OSM_Node(); QString* getLatitude(); QString* getLongitude(); private: QString *latitude; QString *longitude; }; #endif // OSM_NODE_H #ifndef OSM_RELATION_H #define OSM_RELATION_H #include <QHash> #include <QString> class OSM_Relation { public: OSM_Relation(); ~OSM_Relation(); void fillWayList(QString *way); QList<QString*>* getWayList(); private: QList<QString*> *wayList; }; #endif // OSM_RELATION_H #ifndef OSM_WAY_H #define OSM_WAY_H #include <QList> #include <QString> class OSM_Way { public: OSM_Way(); ~OSM_Way(); void fillReferenceList(QString *ref); QList<QString*>* getReferenceList(); private: QList<QString*> *referenceList; }; #endif // OSM_WAY_H
-
Also nur weil es lange dauert ist es nicht falsch, maximal schlecht designt. Habe jetzt nicht die Nerven mich da durchzuwühlen aber hast du es mal im Release-Modus laufen lassen, mit aktivierten Optimierungen?
-
ich habe keine optimierungen vorgenommen, ganz einfach im release modus ausgeführt. visual studio
-
Hast du die Debug-Laufzeitumgebung deaktiviert (indem du das grüne "hohle" Dreieck anklickst oder das Programm direkt aus dem Explorer startest)?
Übrigens: 700 Zeilen ist jenseits von allem, was sich der durchschnittliche Helfer hier anschauen wird. Ein kurzer, problembezogener Code (weniger als 100 Zeilen) und [cpp]- statt [code]-Tags erhöhen die Chancen aber stark.
-
Tja ... verdammt viel
new. Ist nicht unwahrscheinlich, dass Dir da ein Fehler unterlaufen ist. Ich habe auch keinen Nerv, mich da durchzuwühlen. Ich kenne mich auch mit dem ganzen Q-Zeugs nicht aus. Trotzdem ein paar Anmerkungen:Du "verwurstest" hier eine Datenstruktur, die etwas speichern soll, mit einem "Algorithmus", der die Datenstruktur anhand dessen, was in einer Datei steht, befüllen soll. Das sollte man vielleicht entkoppeln. Möglicherweise so:
class osm : boost::noncopyable { // interner Aufbau der Datenstruktur public: … void clear(); … }; void parse_osm(QString fromFile, osm & into);Wenn's sein muss, kann parse_osm auch eine Elementfunktion sein. So etwas wie file, reader, stop hat in der Datenstruktur natürlich nichts zu suchen. Hier kannst Du zB auf RAII setzen:
void parse_osm(QString fromFile, osm & into) { into.clear(); QFile file; QXmlStreamReader reader; … }Beachte: new/delete für QFile und QXmlStreamReader gespart.
Tipp: Versuche mit RAII die Verantwortung für die Verwaltung von Objekten (im Sinne der Lebenszeit) zu deligieren/kapseln. RAII bedeutet jetzt nicht, dass man eine große komplexe Klasse bauen muss, die einen "langen" und komplizierten Destruktor hat. Man kann die Komplexität oft in kleinere Blöckchen zerhacken (separation of concerns) und das große ganze aus diesen kleinen Blöckchen zusammenstecken. Man kommt nicht immer drum herum. Aber versuchen kann man es. Wenn ich eine Klasse so schreiben kann, dass ich keine benutzerdefinierten Funktionen für das Kopieren, Zuweisen und Zerstören benötige, tue ich das auch.
kk
-
habe den code erheblich gekürzt und versucht nur die relevanten informationen reinzunehmen
die 3 klassen/objekte :
#ifndef OSM_NODE_H #define OSM_NODE_H #include <QString> class OSM_Node { public: OSM_Node(QString *lat, QString *lon); OSM_Node::~OSM_Node(); QString* getLatitude(); QString* getLongitude(); private: QString *latitude; QString *longitude; }; #endif // OSM_NODE_H #ifndef OSM_RELATION_H #define OSM_RELATION_H #include <QHash> #include <QString> class OSM_Relation { public: OSM_Relation(); ~OSM_Relation(); void fillWayList(QString *way); QList<QString*>* getWayList(); private: QList<QString*> *wayList; }; #endif // OSM_RELATION_H #ifndef OSM_WAY_H #define OSM_WAY_H #include <QList> #include <QString> class OSM_Way { public: OSM_Way(); ~OSM_Way(); void fillReferenceList(QString *ref); QList<QString*>* getReferenceList(); private: QList<QString*> *referenceList; };im parser werden diese beispielsweise so erzeugt :
node = new OSM_Node(new QString(reader->attributes().value("lat").toString()),new QString(reader->attributes().value("lon").toString())); nodeContainer.insert(new QString(reader->attributes().value("id").toString()),node);way = new OSM_Way(); wayContainer.insert(new QString(reader->attributes().value("id").toString()),way); way->fillReferenceList(new QString(reader->attributes().value("ref").toString()));relation = new OSM_Relation(); relationContainer.insert(new QString(reader->attributes().value("id").toString()),relation); rel->fillWayList(new QString(reader->attributes().value("ref").toString()));wenn der parser abgearbeitet ist soll mit der clear methode alles wieder freigebeben werden
void OSM_Parser::clear() { if(!relationContainer.isEmpty()) { qDebug() << "relationContainer"; QHashIterator<QString*, OSM_Relation*> i(relationContainer); while (i.hasNext()) { //qDebug() << "delete relation"; i.next(); delete i.key(); delete i.value(); } relationContainer.clear(); } if(!wayContainer.isEmpty()) { //qDebug() << "wayContainer"; QHashIterator<QString*, OSM_Way*> x(wayContainer); while (x.hasNext()) { //qDebug() << "delete way"; x.next(); delete x.key(); delete x.value(); } wayContainer.clear(); } if(!nodeContainer.isEmpty()) { //qDebug() << "nodeContainer"; QHashIterator<QString*, OSM_Node*> k(nodeContainer); while (k.hasNext()) { //qDebug() << "delete node"; k.next(); delete k.key(); delete k.value(); } nodeContainer.clear(); } #endif // OSM_PARSER_H
-
so, habe mein programm mal ohne laufzeitumgebung, also direkt über die exe gestartet und siehe da, alles funktioinert einwandfrei. da ich noch nie solch ein großes projekt mit dieser anzahl an daten geschrieben habe, wusste ich nicht das die laufzeitumgebung einfluß auf die ausführung hat.
jetzt stellt sich mir nur noch die frage wann es sinnvoll wäre mit new zu arbeiten und wann nicht. habe letztendlich jedes objekt das ich zwischenspeichere mit new erzeugt. sollte ich da eventuall anders vorgehen, der quellcode ist im post davor.
-
Da C++ nicht Java ist, sollte man new nur dort anwenden, wo es sinnvoll ist. Und das ist dann der Fall, wenn man ein Objekt braucht, was über den Gültigkeitsbereich hinaus existiert. Oder wenn man nicht weiß, wie groß ein Array später sein wird. Oder wenn man mit virtuellen Klassen + Vererbung, etc. arbeitet.
Ich kenne QString nicht, da ich noch nie mit Qt gearbeitet habe. Aber ich gehe mal davon aus, dass es NICHT notwendig ist, dieses Objekt dynamisch anzulegen!
Selbiges gilt für die QList und vermutlich viele weitere deiner Objekte.
// Kein new std::string str = "Hallo"; // Größe zum Kompilierzeitpunkt unbekannt char *arr = new char[x];
-
Viel zu viel new/delete. Du solltest Dir einen ganz anderen Programmierstil zulegen. C++ in einem Java-Stil programmieren ist eine blöde Idee.
-
Bei Qt haben eigentlich fast alle Klassen die schöne Funktion deleteLater() die meist ausreicht. Vorteil: Wenn du das zweimal aufrufst schmiert nichts ab. Nachteil: Du kannst nicht direkt beeinflussen wann es gelöscht wird. So das aber egal ist, ist das die sichere Variante.
Auch brauchst du die QStrings nicht per new anlegen. Überhaupt braucht man nur sehr sehr selten Pointer auf QStrings.