2017-04-10 528 views
-1

我正在使用QList来存储从SQL表中读取的数据。该表有超过一百万条记录。我需要将它们放入列表中,然后在列表中进行一些处理。当大小很大时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:内存不足”错误。

当列表达到< 1197762项>的大小时程序崩溃。我尝试使用reserve(),但它不起作用。 QList是否限于特定的大小?

+1

您的RAM被限制为特定大小。 – Kane

+0

你能看到你的程序使用的内存是否超过了你的机器上安装的内存。 – basslo

+0

“QList崩溃...”不,它没有。班级不会崩溃;应用程序崩溃了。 – MrEricSir

回答

3

您已经耗尽内存,因为C++运行时报告它无法分配更多内存。 Qt容器不是问题。由于指数使用的尺寸为int,因此容器数量限制为2^31-1。你远远没有。

最低限度:

  1. 使用QVector而不是QList因为它对于QVariantMap元素大大降低开销。

  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中。相反,我一次只能处理一个记录。谢谢你的建议。 – medasumanth

0

你要么是没有足够的内存,或者更可能使用的是32位的Qt构建,不能使用超过4 GB的RAM。或者也许两个。尺寸明智的容器本身应该能够处理超过20亿个元素。

QList也没有帮助,因为在你的情况下,它可能会存储每个元素作为指针,并为实际的变体映射做一个额外的堆分配。所以你最终会得到相当大的额外堆分配开销。

而且由于查询已经包含大量的数据,它可能会吃一个体面的ram本身。

除非你禁用页面文件,否则自己用尽RAM不应该导致崩溃,因为它只是开始分页和破坏性能,但保持运行,所以你可能会达到32位的内存限制过程,可能只有2 GB。

除了做库巴在他的回答中提出的建议之外,您可能希望将查询拆分为更小的部分,并在几次查询中得到结果,而不是一次查询结果,并逐个处理它们,从而减少查询结果使用的内存,并在您完成查询后释放查询的内存。

如果你有很多重复字符串,还可以选择从QString保存在RAM中。由于它是隐含共享的,所以可以有一堆相同的字符串,它们都使用相同的基础数据。您可以利用此优势,通过使用QSet来保存唯一字符串的集合并快速检查字符串是否已存在。然后,不要使用查询结果中的字符串,而要使用集合中的字符串。从该集合中复制的所有相同的字符串将重用相同的字符串数据。相比之下,您目前的方法将为每n个重复的字符串使用n个空间量。

+0

感谢您的回复。我会尝试使用你建议的选项。目标计算机只有2 GB的RAM空间,并且该应用程序也是32位的。 – medasumanth

+0

@medasumanth - 请检查我对这些字符串所做的最后一项添加,也许能够为您节省额外的内存。 – dtech

+0

“你要么没有足够的内存,要么更可能使用32位Qt build [...]”,或者只是没有足够大的*连续内存块,哪一个通常会更快速地运行 –