大时 QList 崩溃
QList crashes when size is large
我正在使用 QList 来存储从 SQL Table 中读取的数据。 table 有超过一百万条记录。我需要将它们放入列表中,然后对列表进行一些处理。
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, line 534: Out of memory" 错误。
当列表达到 <1197762 项> 的大小时程序崩溃。我尝试使用 reserve() 但它没有用。 QList 是否有特定大小限制?
您 运行 内存不足,因为 C++ 运行时报告它无法分配更多内存。 Qt 容器不是问题。由于 int
用于索引的大小,容器限制为 2^31-1 个项目。你离那个还差得很远。
至少:
使用 QVector
而不是 QList
,因为它对 QVariantMap
元素的开销要低得多。
如果查询允许,尝试保留 space:这将几乎减半内存需求!
如果可以,请编译 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
也无济于事,因为在您的情况下,它可能会将每个元素存储为指针,并为实际的变体映射进行额外的堆分配。所以你最终会有相当大的额外堆分配开销。
并且由于查询已经包含大量数据,它本身可能会占用相当数量的 ram。
除非你禁用了页面文件,运行 自己从 ram 中退出应该不会导致崩溃,因为它只会开始分页并破坏性能,但保持 运行,所以你是可能达到 32 位进程的内存限制,可能低至仅 2 GB。
除了执行 Kuba 在他的回答中建议的事情之外,您可能希望将查询分成更小的部分,并尽可能在几个查询而不是一个查询中获得结果,并一次处理一个,减少查询结果使用的内存,并在完成查询后释放内存用于查询。
如果您有很多重复字符串,还可以选择从 QString
保存到 RAM 中。由于它是隐式共享的,因此您可以拥有一堆相同的字符串,它们都使用相同的基础数据。您可以利用这一点,通过使用 QSet
来保存唯一字符串的集合并快速检查字符串是否已经存在。然后不使用查询结果中的字符串,而是使用集合中的字符串。从集合中按值复制的所有相同字符串将重用相同的字符串数据。相反,您当前的方法将为每 n 个重复的字符串使用 n 个 space。
我正在使用 QList 来存储从 SQL Table 中读取的数据。 table 有超过一百万条记录。我需要将它们放入列表中,然后对列表进行一些处理。
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, line 534: Out of memory" 错误。
当列表达到 <1197762 项> 的大小时程序崩溃。我尝试使用 reserve() 但它没有用。 QList 是否有特定大小限制?
您 运行 内存不足,因为 C++ 运行时报告它无法分配更多内存。 Qt 容器不是问题。由于 int
用于索引的大小,容器限制为 2^31-1 个项目。你离那个还差得很远。
至少:
使用
QVector
而不是QList
,因为它对QVariantMap
元素的开销要低得多。如果查询允许,尝试保留 space:这将几乎减半内存需求!
如果可以,请编译 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
也无济于事,因为在您的情况下,它可能会将每个元素存储为指针,并为实际的变体映射进行额外的堆分配。所以你最终会有相当大的额外堆分配开销。
并且由于查询已经包含大量数据,它本身可能会占用相当数量的 ram。
除非你禁用了页面文件,运行 自己从 ram 中退出应该不会导致崩溃,因为它只会开始分页并破坏性能,但保持 运行,所以你是可能达到 32 位进程的内存限制,可能低至仅 2 GB。
除了执行 Kuba 在他的回答中建议的事情之外,您可能希望将查询分成更小的部分,并尽可能在几个查询而不是一个查询中获得结果,并一次处理一个,减少查询结果使用的内存,并在完成查询后释放内存用于查询。
如果您有很多重复字符串,还可以选择从 QString
保存到 RAM 中。由于它是隐式共享的,因此您可以拥有一堆相同的字符串,它们都使用相同的基础数据。您可以利用这一点,通过使用 QSet
来保存唯一字符串的集合并快速检查字符串是否已经存在。然后不使用查询结果中的字符串,而是使用集合中的字符串。从集合中按值复制的所有相同字符串将重用相同的字符串数据。相反,您当前的方法将为每 n 个重复的字符串使用 n 个 space。