【问题标题】:C++ allocating large array on heap gives "out of memory exception"C++ 在堆上分配大数组给出“内存不足异常”
【发布时间】:2014-06-28 13:32:57
【问题描述】:

我目前在用数据声明或填充大型数组时遇到问题,因为我收到一个对话框,提示“内存不足”,源自 CMemoryException。

我正在尝试创建一个包含大约 50000 个对象元素的数组或向量(两者都尝试过),其中 sizeof(MyObjectClass) 返回大约 37000 个字节。

如果我尝试逐个元素地填充向量或 CArray,那么我会在出现内存不足异常之前先填充近 16000 个元素。那应该接近 600MB?

我的机器上有 8GB RAM,根据 Windows 任务管理器,只有 4GB 正在使用。因此,物理 RAM 的数量不应成为问题。我在 Visual Studio 2010 32 位中运行 C++ MFC。

如果我尝试写作

MyObjectClass* heaparray = new MyObjectClass[50000];

然后我立即在该行上遇到同样的内存不足错误。

有什么想法吗? 提前谢谢你!

更新: 我也尝试过简单地创建一个带有字段的 TestStruct:

struct TestStruct
{
  long long field1;
  GUID field2;
  GUID field3;
  GUID field4;
  TCHAR field5[256];
  TCHAR field6[4];
  TCHAR field7[258];
  TCHAR field8[1026];
  TCHAR field9[258];
  TCHAR field10[16386];
  TCHAR field11[258];
};

TestStruct* heapArr = new TestStruct[50000];

还是一样...执行最后一行代码时出现“内存不足”异常。 在处理大数据时,堆的好处之一不应该是仅受 RAM(或多或少)的限制。然而......因为它已经在 600MB 的分配空间时崩溃了,所以我不能同意这是非常大的数据......或者我应该吗? :/

【问题讨论】:

  • MyObjectClass 是什么样的?
  • 在 32 位编译器上分配超过 4GB 的可能性不大
  • 如果每个 obj 真的是 37000 字节,那么您至少需要 1764.16 MB
  • 另外,您正在请求大量连续内存,即使您有大量物理内存也无法使用
  • 即使您使用的是 64 位操作系统并拥有 8GB 内存,默认情况下,32 位用户模式进程也只能访问 2GB 内存。见:this question。你不能把你的程序编译成 x64 版本吗?

标签: c++ arrays memory


【解决方案1】:

这是一个有趣的。如here 所述,向量和数组都连续存储在内存中。

您不仅要在内存中寻找1850000000 bytes (1.72295 gigabytes),还要一块完整的大块内存。那将很难找到。如果您切换到不进行连续存储的其他数据结构(例如链接列表),那么您可能能够存储那么多。

注意:这也会使每个对象变大一点。

最好的办法是看看是否有任何方法可以缓冲对象;仅加载您将更新的内容,并在需要时即时加载其他内容。我怀疑您一次对多个 CPU 进行操作。如果你做对了(很可能使用线程),你甚至不会因为读/写它们而受到任何减慢。

有关您正在从事的工作的更多信息会有所帮助。如果您的对象的变体少于 2,147,483,647(int 大小),甚至可能有一种方法可以只填充一个类型标识符的数组。您可以存储一个可以从中生成类的整数数组(一个 toHash 和 fromHash 将是 50000 * 4 字节 = 195.312 千字节),这也可能对您有用。同样,这取决于您在做什么。

【讨论】:

  • 感谢您的回复!我需要从数据库(网络)中获取很多行,然后对每个行执行一些操作,然后将其全部刷新到本地数据库表中。所以,我可以分配大量内存而不是多次往返网络数据库。所以我有一个 CCommand> cmd。我使用获取大量数据(大约 50000 行)的 ans SQL 查询调用 cmd.Open(),然后循环直到 cmd.MoveNext() 失败。每一轮循环我都将当前元素添加到向量或数组中。在 16000 行之后,我得到内存异常。链表...也许我应该尝试一下我刚刚做过的>
  • > 不相信我无法使用数组/向量更轻松地在堆上分配这么多 RAM ......因为它在仅分配 600MB 后崩溃:/(另请参阅我的 uopdate 部分第一篇)
  • 连续存储只是虚拟内存的意义。它只需要虚拟内存地址的连续范围,而不是物理存储。
  • 好的,现在我有时间用 std:list 进行测试,是的,它确实有效!连续记忆似乎是原因。谢谢你的回答!
【解决方案2】:

我将尝试扩展@user1884803 的答案:

  1. 不要使用指向数组的指针。甚至 Visual Studio 2010 也有 <vector>。但请看下一点。

  2. 也不要使用vector...特别是如果您真的想要读取 RAM 中的所有 MyObjectClass 对象。正如另一个答案所说,即使您有 4GB 的空闲空间,您也可能没有有 1.7GB 的连续可用内存

  3. 1234563 std::list<MyObjectClass> 或者,如果您需要“密钥”来访问每条记录,请使用 std::map<KeyType, MyObjectClass>但是...
  4. 您确实应该尝试将 1.8GB 的​​对象读取到 RAM。即使您有那么多未使用的 RAM,这也只是 不是一个好习惯。如果可以的话,从数据库中读取每个对象,对其进行处理,然后将其写回数据库丢弃使用过的对象,而不是将整个对象存储在 RAM 中。如果您需要并且如果它提高了您的速度,您可以将其中的一部分保存在 std::liststd::map 甚至 std::vector 中,并且按需刷新对象的其他部分来自数据库。

这样,您的程序将从:

if( cmd.Open() ) {
  do {
    MyObjectClass obj = cmd.Read(); // whatever is needed to read the object from the db
    vectorOfObjects.push_back(obj); // or list, or map...
  } while( cmd.MoveNext() );
}

for( std::vector<MyObjectClass>::iterator p = vectorOfObjects.begin(), e = vectorOfObjects.end(); p != e; ++p ) {
  // process *p
}

for( std::vector<MyObjectClass>::iterator p = vectorOfObjects.begin(), e = vectorOfObjects.end(); p != e; ++p ) {
  cmd.Save(*p); // see reading above, but for saving...
}

类似

if( cmd.Open() ) {
  do {
    MyObjectClass obj = cmd.Read();
    // JUST PROCESS obj here and go to next

    cmd.Save(obj); // or whatever
  } while( cmd.MoveNext() );
}

【讨论】:

  • 感谢您的回复!是的,但我明白你的意思,但问题是最终所有这些数据都需要以某种形式从一个网络数据库传输到本地数据库表。通过逐行获取到远处的网络数据库进行 50000 次往返,然后在处理每个数据后还逐行保存(这次另外 50000 次往返本地服务器)花费了太多时间(这是今天的问题)。所以我不知道在这个时间范围内我还有什么其他方便的选择......
  • @user2506124 你知道你必须逐行获取和保存,即使使用CCommand&lt;CAccessor&lt;MyObjectClass&gt;&gt; 并且CCommand 将比你尝试放置它们更有效地缓存你的记录在数组中...
  • 是的,我知道获取将是逐行进行的,但我发现通过调用 cmd.MoveNext() 比当前获取的其他方法提高了 10 倍的网络利用率,也许更多当命令的 sql 查询一次获取多于一行时,数据是否被缓存?此外,当我创建一个带有插入语句的大型 SQL 字符串并将其发送到 SQL Server 时,当保存回其他数据库时,我得到的性能明显高于当前使用的解决方案。
  • 我对 CCommand 还很陌生,所以我可能无法详细解释为什么一切都会发生,只是观察我所看到的解决问题的不同方法的效果。感谢您的帮助!
  • @user2506124 :: “当前获取方法” 是什么?也许我可以调整我的答案来帮助你更多。
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 2017-06-25
  • 2012-01-23
  • 2012-02-03
  • 2016-11-19
  • 1970-01-01
  • 2016-07-27
  • 2010-09-17
相关资源
最近更新 更多