C ++在堆上分配大型数组会导致内存异常"

时间:2014-05-11 00:56:13

标签: c++ arrays memory

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

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

如果我尝试按元素填充向量或CArray元素,那么在获取Out Of Memory异常之前,我会在16000个元素附近填充。那应该接近600MB?

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

如果我试着写

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

仍然相同......执行最后一行代码时出现“Out of Memory”异常。 在处理大数据时,堆不应该只是由RAM(或多或少)限制的可能性之一。然而......因为它已经在600MB的分配空间崩溃了,我不能同意这是非常大的数据......或者我应该? :/

2 个答案:

答案 0 :(得分:5)

这是一个有趣的。 Vector和数组都按照所述here连续存储在内存中。

你不仅在内存中寻找1850000000 bytes1.72295 gigabytes),而且一个完整的大块内存。这很难找到。如果您切换到不执行连续存储的不同数据结构(比如链接列表),那么您可以存储那么多。

注意:这也会使每个对象变得更大。

最好的方法是看看是否有任何方法可以缓冲对象;只加载你要更新的那些,并在需要时动态加载其他的。我怀疑你一次只能在多个CPU上进行cpu操作。如果你做得对(最有可能穿线)你甚至不会因读/写它们而受到任何影响。

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

答案 1 :(得分:2)

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

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

  2. 也不要使用vector ...特别是如果确实想要读取RAM中的所有MyObjectClass个对象。正如另一个答案所说,即使你有4Gbytes免费,你可能拥有1.7Gbytes 连续可用内存

  3. 所以,如果你真的,真的,想要读取RAM中的所有对象(因为你想对它们进行的处理是非线性的,或者在内存中同时需要很多记录),请使用std::list<MyObjectClass>或者,如果您需要“密钥”来访问每条记录,请使用std::map<KeyType, MyObjectClass>。的 BUT ...

  4. 你真的应该尝试读取1.8Gbytes的对象到RAM。即使你有大量RAM未使用,也只是不是一个好习惯。如果可以,请从数据库中读取每个对象,对其进行处理,然后将其写回数据库丢弃已使用的对象,而不是将整个内容累积到RAM中。如果您需要并且如果它可以提高您的速度,您可以将其中一部分保存在std::liststd::map,甚至std::vector按需中从数据库中刷新对象的其他部分。

  5. 这样,您的程序将来自:

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