繁体   English   中英

C ++中std :: vector的内存问题

[英]Memory issue with std::vector in c++

我在c ++中的std :: vector有内存问题。 这是我的代码:

#include <iostream>
#include <vector>
int main () {

  std::vector< std::vector<float> > mesh_points_A;

  int N=10;

  for(int i=0;i<N;i++){ 
    for(int j=0;j<N;j++){ 
      std::vector<float> xyz;
      xyz.push_back(i);
      xyz.push_back(j);
      xyz.push_back(0.3);
      mesh_points_A.push_back(xyz);
    }
  }

  return 0;
}

当我将N增加到10000或更高时,我的内存不足了...但是我认为我做错了什么,因为例如,如果我将python和numpy数组一起使用,这很容易实现...

提前谢谢了。

编辑:这是原始代码。 上面的代码只是为了更好地说明问题而进行的简化。 问题是,是否有可能在保持N = 10000的情况下在不耗尽内存的情况下创建许多Surface对象(在代码中当前有两个)。

// classes example compile with c++ -o Surface Surface.cpp -std=c++11

#include <iostream>
#include <vector>
#include <array>

class Surface {
private:
  std::vector< std::array<float,3> > mesh_points_A; 

public:
  float R;
  float z; // z position if the suface
  int n_A; //number of area mesh points mesh_points_A.size()
  Surface(int nxA, float R , float z); 
};

Surface::Surface(int nxA, float  R,float z)
  : z(z)
  , R(R)
{

  float dxA= 2*R/(nxA*1.0-1.0);
  //determine n_A, 
  n_A=0;
  for(int i=0;i<nxA;i++){ 
    float x = -R+i*dxA;
    for(int j=0;j<nxA;j++){ 
      float y = -R+j*dxA;
      if(x*x+y*y<R*R){
        n_A+=1;
      }
    }
  }
  std::cout<<"Number of area mesh points: "<<n_A<<std::endl;
  mesh_points_A.reserve(n_A);

  for(int i=0;i<nxA;i++){ 
    float x = -R+i*dxA;
    for(int j=0;j<nxA;j++){ 
      float y = -R+j*dxA;
      if(x*x+y*y<R*R){
        std::array<float,3> xyz{ {x,y,z} };
        mesh_points_A.push_back(xyz);       
      }
    }
  }


}



int main () {
  int N= 20000;
  Surface s1(N,0.1,0.0);
  Surface s2(N,0.1,0.1);
  return 0;
}

您的引导程序需要连续重新分配更多内存以保持增长。 它通过保留更大的新内存区域并复制旧数据来做到这一点。 这取决于实现方式,要保留多少内存,但是典型的策略是分配两倍的内存(libstdc ++会这样做)。

这意味着,在最坏的情况下,您的总内存需求可能接近原始内存需求的三倍

假设您的向量当前包含90,000,000个元素,不幸的是,它的容量也是90,000,000 1 要插入90,000,001st元素, std::vector现在将保留两倍的内存— 180,000,000,将所有旧元素复制过来,然后销毁旧数组。

因此,即使“仅”需要100,000,000个元素,您也必须短暂地为270,000,000个元素分配存储。 即使您的100M向量只需要3.35 GiB,也大约相当于9.10 GiB。

通过将以下行放在嵌套初始化循环的前面,可以很好地避免这种情况:

mesh_points_A.reserve(N * N);

1实际上,容量可能是2的幂,例如2 26 = 67,108,864; 大小仍然是6.75 GiB的内存。

std::vector具有根据需要动态更改大小的灵活性。 一如既往,灵活性是有代价的。 通常,该价格很小,可以轻松忽略,尽管在这种情况下,当您使用std::vector<float>std::array<float,3>差异非常大,因为您有1亿个元素。 例如,如果我们运行以下代码:

 std::vector<float> v;
 for( auto f : { 1.0, 2.0, 3.0 } ) v.push_back(f);
 std::cout << sizeof(v) << "-" << v.capacity() << std::endl;
 std::cout << sizeof(std::array<float,3>) << std::endl;

现场例子

我们可以看到,在此平台上, std::vector<float>本身占用24个字节,并且它动态地为4个std::vector<float>分配内存-16个字节,而对于3个float-12字节(如果您使用固定大小的结构)。 因此,在您的情况下,差异将是:

1 std::vector - ( 24 + 16 ) * 100 000 000 = 4 000 000 000
2 std::array  - 12 * 100 000 000          = 1 200 000 000

2 800 000 000或大约2 Gb的内存。

但这还不是std::vector另一项代价-它必须在连续空间中分配所有数据。 通常在大小达到当前大小时通过重新分配容量来完成。 在这种情况下,这意味着创建此数据的内存需求可以轻松翻一番以上-假设如果容量达到5000万,并且vector需要重新分配,那么它将创建另一个内存块,比如说1亿,同时保持先前的内存(因此您的内存必须容纳1.5亿个元素)并进行复制。 而且没有内存碎片问题。

因此,建议的解决方案是将std::array<float,3>用于内部数据(或具有3个元素的struct ),并使用std::deque作为外部容器,或者如果您必须使用std::vector为中的足够元素分配内存预先。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM