2017-04-10 2 views
-1

Ich verwende eine QList, um die aus einer SQL-Tabelle gelesenen Daten zu speichern. Die Tabelle hat mehr als eine Million Datensätze. Ich muss sie in eine Liste bringen und dann auf der Liste etwas bearbeiten.QList stürzt ab, wenn die Größe groß ist

QList<QVariantMap> list; 

QString selectNewDB = QString("SELECT * FROM newDatabase.M106SRData"); 
QSqlQuery selectNewDBQuery = QSqlDatabase::database("CurrentDBConn").exec(selectNewDB); 
while (selectNewDBQuery.next()) 
{ 
    QSqlRecord selectRec = selectNewDBQuery.record(); 
    QVariantMap varMap; 
    QString key; 
    QVariant value; 
    for (int i=0; i < selectRec.count(); ++i) 
    { 
     key = selectRec.fieldName(i); 
     value = selectRec.value(i); 
     varMap.insert(key, value); 
    } 
    list << varMap; 
} 

Ich bekomme "qvector.h, Zeile 534: Nicht genügend Speicher" Fehler.

Das Programm stürzt ab, wenn die Liste die Größe < 1197762 Elemente> erreicht. Ich habe versucht, Reserve(), aber es hat nicht funktioniert. Ist QList auf eine bestimmte Größe beschränkt?

+1

Ihr RAM ist auf eine bestimmte Größe begrenzt. – Kane

+0

Können Sie sehen, ob der von Ihrem Programm verwendete Speicher den auf Ihrem Computer installierten Speicher übersteigt? – basslo

+0

"QList stürzt ab ..." Nein, tat es nicht. Klassen können nicht abstürzen; Was abgestürzt ist, war die Anwendung. – MrEricSir

Antwort

3

Sie haben nicht genügend Arbeitsspeicher, da die C++ - Laufzeit gemeldet hat, dass kein Speicher mehr zugewiesen werden kann. Es ist kein Problem mit Qt-Containern. Die Container sind aufgrund der Größe int der Verwendung für den Index auf 2^31-1 Artikel begrenzt. Du bist nicht in der Nähe.

Am allerwenigsten:

  1. Verwenden Sie ein QVector statt QList, da es viel geringeren Overhead für das QVariantMap Element hat.

  2. Versuch, den Platz zu reservieren, wenn die Abfrage es erlaubt: das wird fast die Speicheranforderungen halbieren!

  3. Kompilieren Sie für ein 64-Bit-Ziel, wenn Sie können.

QVector<QVariantMap> list; 

QString selectNewDB = QString("SELECT * FROM newDatabase.M106SRData"); 
QSqlQuery selectNewDBQuery = QSqlDatabase::database("CurrentDBConn").exec(selectNewDB); 
auto const size = selectNewDBQuery.size(); 
if (size > 0) list.reserve(size); 
while (selectNewDBQuery.next()) 
{ 
    auto selectRec = selectNewDBQuery.record(); 
    QVariantMap varMap; 
    for (int i=0; i < selectRec.count(); ++i) 
    { 
     auto const key = selectRec.fieldName(i); 
     auto const value = selectRec.value(i); 
     varMap.insert(key, value); 
    } 
    list.append(varMap); 
} 
+0

Danke für die Vorschläge. Die Verwendung von QVector hat nicht geholfen. Ja, ich baue mit einem 32-Bit-Qt. Ich werde jetzt versuchen, mit einem 64-Bit zu bauen. – medasumanth

+0

Müssen Sie eine 'QVariantMap' und Varianten selbst speichern? Müssen Sie die redundanten Feldnamen speichern? Nein. Erstellen Sie eine "struct", um die Zeile der Tabelle darzustellen, und speichern Sie diese im 'QVector'. Es wird wahrscheinlich dann funktionieren. Fragen Sie sich auch: Warum verschieben Sie all diese Daten von der Datenbank in den Arbeitsspeicher? Fragen Sie einfach die Datenbank ab, wenn Sie sie brauchen. –

+0

Ja, was du gesagt hast macht Sinn. Ich habe einen Code-Refactor erstellt und ich speichere jetzt nicht das gesamte Ergebnis in QList/QVector. Stattdessen arbeite ich jeweils an einem Datensatz. Danke für deinen Rat. – medasumanth

0

Sie entweder nicht genug RAM, oder eher zu einem 32-Bit-Qt Build verwenden, die nicht mehr als 4 GB RAM nutzen. Oder vielleicht beides. In der Größe sollte der Container selbst in der Lage sein, mehr als 2 Milliarden Elemente zu handhaben.

QList hilft auch nicht, wie in Ihrem Fall wird wahrscheinlich jedes Element als Zeiger speichern und eine zusätzliche Heap-Zuweisung für die tatsächliche Variante Zuordnung. Sie haben also einen erheblichen zusätzlichen Heap-Allokationsaufwand.

Und da die Abfrage bereits eine erhebliche Menge an Daten enthält, isst es wahrscheinlich eine anständige Menge an RAM selbst.

Wenn Sie die Auslagerungsdatei nicht deaktiviert haben, sollte das Auslaufen des Widgets nicht zu einem Absturz führen, da dies die Auslagerungsfunktion beeinträchtigt und die Performance beeinträchtigt, so dass Sie wahrscheinlich das Speicherlimit für 32 Bit erreichen Prozess, der so niedrig wie nur 2 GB sein kann.

Abgesehen von den Dingen, die Kuba in seiner Antwort vorgeschlagen hat, möchten Sie vielleicht Ihre Abfrage in kleinere Teile aufteilen und die Ergebnisse in wenigen Abfragen und nicht, wenn möglich, einzeln verarbeiten und einzeln verarbeiten Speicher, der von den Abfrageergebnissen verwendet wird, und den Speicher für eine Abfrage freigeben, sobald Sie damit fertig sind.

Es gibt auch die Möglichkeit, RAM von QString zu speichern, falls Sie viele sich wiederholende Strings haben. Da es implizit geteilt wird, können Sie eine Reihe von identischen Strings haben, die alle dieselben zugrunde liegenden Daten verwenden. Sie können dies ausnutzen, indem Sie eine verwenden, um eine Sammlung eindeutiger Zeichenfolgen zu behalten, und eine schnelle Überprüfung, ob eine Zeichenfolge bereits vorhanden ist. Verwenden Sie dann anstelle der Zeichenfolge aus dem Abfrageergebnis die Zeichenfolge aus der Gruppe. Alle identischen Zeichenfolgen, die vom Wert aus der Gruppe kopiert wurden, verwenden dieselben Zeichenfolgendaten erneut. Im Gegensatz dazu verwendet Ihr aktueller Ansatz n Platz für alle n doppelten Strings.

+0

Danke für die Antwort. Ich werde mit den vorgeschlagenen Optionen versuchen. Der Zielcomputer hat nur 2 GB RAM-Speicherplatz und die Anwendung ist auch ein 32-Bit-Speicherplatz. – medasumanth

+0

@medasumanth - überprüfe auch den letzten Zusatz, den ich an den Strings gemacht habe, der dir eventuell zusätzlichen Speicher sparen könnte. – dtech

+0

"Entweder haben Sie nicht genug Ram, oder eher verwenden Sie eine 32bit Qt Build [...]" oder einfach nicht ein groß genug Block von * konsekutiven * Speicher, der normalerweise viel schneller läuft. –

Verwandte Themen