QList 在大小较大时崩溃



我正在使用QList来存储从SQL表中读取的数据。该表有超过一百万条记录。我需要将它们放在列表中,然后在列表中进行一些处理。

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 是否仅限于特定大小?

内存不足,因为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);
}

您要么没有足够的内存,要么更有可能使用的是 32 位 Qt 构建,它不能利用超过 4 GB 的内存。或者两者兼而有之。从尺寸上看,容器本身应该能够处理超过20亿个元素。

QList也无济于事,因为在你的情况下,它可能会将每个元素存储为指针,并为实际的变体映射进行额外的堆分配。因此,您最终会得到相当大的额外堆分配开销。

而且由于查询已经包含大量数据,因此它本身可能会消耗相当数量的内存。

除非您禁用了 pagefile,否则 ram 本身不足不会导致崩溃,因为它只会开始分页并破坏性能,但会继续运行,因此您可能会达到 32 位进程的内存限制,可能低至 2 GB。

除了执行 Kuba 在他的答案中建议的操作之外,您可能还希望将查询拆分为更小的部分,并在几个查询中获取结果,如果可能的话,而不是一个查询,并一次处理一个,从而减少查询结果使用的内存,并在完成查询后释放查询的内存。

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

相关内容

  • 没有找到相关文章

最新更新