2017-04-10 21 views
-1

SQLテーブルから読み取ったデータを格納するためにQListを使用しています。テーブルには100万を超えるレコードがあります。私はそれらをリストに入れ、リスト上で何らかの処理をする必要があります。サイズが大きいとQListがクラッシュする

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; 
} 

「qvector.h、行534:Out of memory」エラーが表示されます。

リストが< 1197762アイテムのサイズに達すると、プログラムがクラッシュします。私は予備()を使用してみましたが、動作しませんでした。 QListは特定のサイズに制限されていますか?

+1

RAMは特定のサイズに制限されています。 – Kane

+0

プログラムで使用されているメモリが、マシンにインストールされているメモリを超えているかどうかを確認できますか。 – basslo

+0

"QListがクラッシュする..."いいえ、そうではありませんでした。クラスはクラッシュすることはできません。アプリケーションがクラッシュしました。 – MrEricSir

答えて

3

C++ランタイムがメモリをそれ以上割り当てできないと報告したため、メモリが不足しています。 Qtのコンテナには問題ありません。コンテナは、インデックス用のintのサイズのため、2^31-1アイテムに制限されています。あなたはその近くにいません。非常に少なくとも

  1. それはQVariantMap要素のためのはるかに低いオーバーヘッドを持っているとして、代わりにQListQVectorを使用してください。

  2. クエリで許可されている場合は、空き領域を確保しようとすると、メモリ要件がほぼ半分になります。

  3. 可能であれば、64ビットターゲット用にコンパイルしてください。

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

おかげさまで、ありがとうございました。 QVectorを使用しても役に立ちませんでした。はい、私は32ビットQtを使用してビルドしています。私は今64ビットを使ってビルドを試みます。 – medasumanth

+0

'QVariantMap'とその変形を保存する必要がありますか?冗長フィールド名を格納する必要がありますか?いいえ。テーブルの行を表す 'struct'を作成し、' QVector'に格納します。おそらくそれはうまくいくでしょう。また、なぜあなたはデータベースからRAMにすべてのデータを移動しているのですか?必要なときにデータベースに問い合わせるだけです。 –

+0

はい、あなたが言ったことは意味がありました。私はいくつかのコードリファクタを行い、QList/QVectorに結果セット全体を保存していません。代わりに私は一度に1つのレコードに取り組んでいます。アドバイスありがとうございます。 – medasumanth

0

あなたは十分なRAMを持っていない、または可能性が高いラムの4 GB以上を利用することができない32bit版Qtのビルドを使用しているのどちらか。あるいは両方とも。サイズ自体は、容器自体が20億以上の要素を扱うことができるはずです。

QListはどちらの場合でも役に立ちますが、実際のバリアントマップには、すべての要素をポインタとして格納し、追加のヒープ割り当てを行う可能性があります。したがって、かなりのヒープ割り当てオーバーヘッドが発生します。

クエリにはすでにかなりの量のデータが含まれているため、おそらくラムそのものをかなり食べるでしょう。

pagefileを無効にしていない限り、単独でRAMを使い果たしても、ページングを開始してパフォーマンスが低下しますが、稼働し続けるため、32ビットのメモリ制限に達する可能性がありますプロセスはわずか2GBにしかならないかもしれません。

答えでクバが示唆したこととは別に、クエリをより細かく分割し、可能な場合は1つずつクエリを実行し、結果を1つずつ処理してクエリ結果によって使用されるメモリであり、完了したらクエリのメモリを解放します。

リピート文字列が多い場合は、QStringからRAMに保存するオプションもあります。暗黙的に共有されているので、すべて同じ基本データを使用する一連の同一の文字列を持つことができます。一意の文字列のコレクションを保持するためにQSetを使用し、文字列が既に存在するかどうかを素早くチェックすることで、これを利用できます。次に、クエリ結果の文字列を使用する代わりに、セットの文字列を使用します。セットから値によってコピーされたすべての同一の文字列は、同じ文字列データを再利用します。これとは対照的に、現在のアプローチでは、複製されたn個の文字列ごとにn個のスペースが使用されます。

+0

お返事ありがとうございます。あなたが提案したオプションを試してみます。ターゲットコンピュータには2 GBのRAM容量しかなく、アプリケーションは32ビットのものです。 – medasumanth

+0

@medasumanth - 最後に追加した文字列をチェックして、余分なメモリを節約できます。 – dtech

+0

"あなたは十分なRAMを持っていないか、32ビットQtビルド[...]を使用している可能性が高いです - または、通常ははるかに速く実行される*連続したメモリブロックではありません –

関連する問題