简体   繁体   English

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

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

I am having a memory issue with std:: vector in c++. 我在c ++中的std :: vector有内存问题。 Here is my code: 这是我的代码:

#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;
}

When I increase N to 10000 or higher I am running out of memory... But I think that I am doing something totally wrong, because if I would for example use python with numpy arrays this would be possible easily... 当我将N增加到10000或更高时,我的内存不足了...但是我认为我做错了什么,因为例如,如果我将python和numpy数组一起使用,这很容易实现...

Many thanks in advance. 提前谢谢了。

EDIT: This is the original code. 编辑:这是原始代码。 The above code was just a simplification to exemplify the problem better. 上面的代码只是为了更好地说明问题而进行的简化。 The question is, if it is somehow possible to create many Surface objects (in the code there are currently two) without running out of memory while keeping N=10000. 问题是,是否有可能在保持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;
}

Your vector needs to successively reallocate more memory to keep growing. 您的引导程序需要连续重新分配更多内存以保持增长。 It does this by reserving a new, larger area of memory and copying the old data over. 它通过保留更大的新内存区域并复制旧数据来做到这一点。 It depends on the implementation how much more memory is reserved, but a typical strategy is to allocate twice as much memory (libstdc++ does this). 这取决于实现方式,要保留多少内存,但是典型的策略是分配两倍的内存(libstdc ++会这样做)。

This means that, in the worst case, your total memory requirement could be close to three times as much as your raw memory requirement: 这意味着,在最坏的情况下,您的总内存需求可能接近原始内存需求的三倍

Let's say your vector currently holds 90,000,000 elements, and its capacity — by bad luck — is also 90,000,000 1 . 假设您的向量当前包含90,000,000个元素,不幸的是,它的容量也是90,000,000 1 To insert the 90,000,001st element, std::vector now reserves twice as much memory — 180,000,000, copies all the old elements over, and then destructs the old array. 要插入90,000,001st元素, std::vector现在将保留两倍的内存— 180,000,000,将所有旧元素复制过来,然后销毁旧数组。

Therefore, even though you “only” need 100,000,000 elements, you briefly had to allocate storage for 270,000,000 elements. 因此,即使“仅”需要100,000,000个元素,您也必须短暂地为270,000,000个元素分配存储。 This corresponds to around 9.10 GiB, even though your 100M vector only requires 3.35 GiB. 即使您的100M向量只需要3.35 GiB,也大约相当于9.10 GiB。

This can be neatly avoided by putting the following line in front of your nested initialisation loop: 通过将以下行放在嵌套初始化循环的前面,可以很好地避免这种情况:

mesh_points_A.reserve(N * N);

1 More realistically, the capacity is probably a power of two, eg 2 26 = 67,108,864; 1实际上,容量可能是2的幂,例如2 26 = 67,108,864; that's still 6.75 GiB of memory for the resizing. 大小仍然是6.75 GiB的内存。

std::vector has a flexibility of dynamically change size on your need. std::vector具有根据需要动态更改大小的灵活性。 As always flexibility has a price. 一如既往,灵活性是有代价的。 Usually that price is small and can be easily ignored though in this case when you use std::vector<float> vs std::array<float,3> difference is very significant as you have 100 million of elements. 通常,该价格很小,可以轻松忽略,尽管在这种情况下,当您使用std::vector<float>std::array<float,3>差异非常大,因为您有1亿个元素。 For example if we run this code: 例如,如果我们运行以下代码:

 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;

live example 现场例子

we can see that on this platform std::vector<float> itself takes 24 bytes plus it dynamically allocate memory for 4 floats - 16 bytes vs just 3 floats - 12 bytes if you would use fixed size structure. 我们可以看到,在此平台上, std::vector<float>本身占用24个字节,并且它动态地为4个std::vector<float>分配内存-16个字节,而对于3个float-12字节(如果您使用固定大小的结构)。 So in your case difference would be: 因此,在您的情况下,差异将是:

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 or around 2Gb of memory. 2 800 000 000或大约2 Gb的内存。

But that not the end of it std::vector has another price - it must allocate all data in continuous space. 但这还不是std::vector另一项代价-它必须在连续空间中分配所有数据。 Usually it is done be reallocating capacity when size reaches current one. 通常在大小达到当前大小时通过重新分配容量来完成。 In this case it means that memory need for creating this data can be easily more than doubled - let's say if capacity reaches 50 million and vector needs to reallocate, it would create another block of memory for lets say 100 million while keeping previous one (so you memory has to hold 150 million elements) and copy them. 在这种情况下,这意味着创建此数据的内存需求可以轻松翻一番以上-假设如果容量达到5000万,并且vector需要重新分配,那么它将创建另一个内存块,比如说1亿,同时保持先前的内存(因此您的内存必须容纳1.5亿个元素)并进行复制。 And that without memory fragmentation issue. 而且没有内存碎片问题。

So recommended solution is to have std::array<float,3> for inner data (or struct with 3 elements) and either std::deque as outer container or if you have to use std::vector allocate memory for enough elements in advance. 因此,建议的解决方案是将std::array<float,3>用于内部数据(或具有3个元素的struct ),并使用std::deque作为外部容器,或者如果您必须使用std::vector为中的足够元素分配内存预先。

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

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