超大 3D 阵列的内存管理

Posted

技术标签:

【中文标题】超大 3D 阵列的内存管理【英文标题】:Memory Management of Very Large 3D Array 【发布时间】:2014-03-13 20:38:31 【问题描述】:

我需要制作一个非常大的 3D 数组。大,我的意思是6000x1000x1000。每个元素都包含一个包含 3 个双精度的结构。该数组表示一个物理向量场,每个数组元素都包含向量值。

我需要动态声明数组,并且已经阅读了两种方法:使用向量类或使用指针。两个例子如下所示:

#include<iostream>
using namespace std;

struct myVector 
    double Bx;
    double By;
    double Bz;
;

#define HEIGHT 10
#define WIDTH 10
#define DEPTH 50
//these are your sizes

void fill(myVector ***p3DArray);
void print(myVector ***const p3DArray);

int main() 
   myVector ***p3DArray; //any name you want

  // Allocate memory
  // Replace "Struct" with the name of your struct
  p3DArray = new myVector**[HEIGHT];
  for (int i = 0; i < HEIGHT; ++i) 
    p3DArray[i] = new myVector*[WIDTH];

    for (int j = 0; j < WIDTH; ++j)
      p3DArray[i][j] = new myVector[DEPTH];
  

  // Assign values
  p3DArray[0][0][0].Bx = 3.6;
  p3DArray[1][2][4].Bz = 4.0;

  fill(p3DArray);
  //print(p3DArray);

  // De-Allocate memory to prevent memory leak
  for (int i = 0; i < HEIGHT; ++i) 
    for (int j = 0; j < WIDTH; ++j)
      delete [] p3DArray[i][j];

    delete [] p3DArray[i];
  
  delete [] p3DArray;

  return 0;

#include <vector>
#include <iostream>
using namespace std;


struct myVector 
    double Bx;
    double By;
    double Bz;
;

#define HEIGHT 1000
#define WIDTH 1000
#define DEPTH 500

void fill(vector<vector<vector<myVector>>> &Array);
void print(vector<vector<vector<myVector>>> &Array);

int main() 
  vector<vector<vector<myVector> > > array3D;

  // Set up sizes. (HEIGHT x WIDTH)
  array3D.resize(HEIGHT);
  for (int i = 0; i < HEIGHT; ++i) 
    array3D[i].resize(WIDTH);

    for (int j = 0; j < WIDTH; ++j)
      array3D[i][j].resize(DEPTH);
  

  // Put some values in
  array3D[1][2][5].Bx = 6.0;
  array3D[3][1][4].By = 5.5;

  fill(array3D);

  return 0;

对于 1000x1000x500 的尺寸,我的计算机内存不足并死机。我需要比这更大。使用 sizeof(),我发现单个元素占用 24 个字节。对于 1000x1000x500 元素,即 12 Gb。我正在使用 Microsoft Visual c++ 2010、64 位调试器和操作系统,并且有 8 Gb 的 RAM。

我只是没有足够的 RAM,还是有更好的方法来做到这一点?

谢谢

【问题讨论】:

你不能把你的问题分解成更小的元素吗? 首先,如果您要使用这样的老式数组,请将它们保存在 std::unique_ptr 中,这样您就不会忘记删除它们。您不想同时在内存中塞满这么多数据......典型的替代方法是流式传输(即一次处理一小部分数据),或者如果这不起作用,则将数据存储在数据库或只是在磁盘上的块中,可以根据需要将其提取到内存中。 哇……现在这是一个大数组……即使您可以改进它,也可能需要更多内存。 【参考方案1】:

要达到 6000x1000x1000 的目标,您无法一次将所有数据存储在 RAM 中。对于这么多元素,每个元素 24 字节,你说的是大约 134 GB 的数据。

您可能想要做的是设计自己的类,该类从磁盘检索元素,而不是将所有内容分配到单个连续的内存块中。

【讨论】:

【参考方案2】:

编写一个对客户端隐藏存储实现的类(我们称之为“3dArray”)。在该类中,您不应存储 3D 数组的全部内容存储明确写入的值。在您的示例中,您只设置了两个数据点,那么为什么不只存储这两个数据点(以任何方式)?为此,请摆脱需要具有 HEIGHT x WIDTH x DEPTH 元素的向量或数组的想法。相反,使用类似的东西:

std::map<Coord, myVector> written_points;

...

void 3dArray::SetPoint(int x, int y, int z, myVector const &value)

    written_points[Coord(x, y, z)] = value; 

此外,在返回操作结果时,返回延迟实际计算的代理对象。

例如,假设你的类应该支持乘法:

3dArray a1;
3dArray a2;
3dArray a3 = multiply(a1, a2);
std::cout << a3.GetPoint(10, 20, 30);

乘法的结果在这里几乎完全被丢弃 - 只需要整个巨大结果的一个数据点。为什么要乘以整个事物?如果您觉得这个想法很有趣,请查看 Scott Meyers 的 More Effective C++ 书中的第 17 条:“考虑使用惰性求值”。

最后,请记住,任何此类优化技术的有效性取决于数据在您的应用程序中的使用方式。

【讨论】:

代码主要取自 C++.com。实际上,我将使用所有的点,而不是其中的两个。所以,我确实会写下所有的价值观。首先,我创建数组,然后将其填充满值(因此是任意填充函数)。然后我将在我的向量场分析中使用这些值。如果我理解,那仍然会减轻我自己的课程,对吗? 好吧,如果你真的一直需要 all 元素,那么实际上使用惰性求值是没有意义的,你不得不求助于磁盘存储。但是,请考虑一下:如果 99%(或 90%,甚至可能 50%)的点数为 0,该怎么办?在那种情况下,只存储 0的少数点的坐标和值仍然很有意义,不是吗?因此,它不仅取决于您执行的操作,还取决于您希望表示的数据类型。无论如何,是的,在这里制作自己的课程是个好主意。

以上是关于超大 3D 阵列的内存管理的主要内容,如果未能解决你的问题,请参考以下文章

Unity 3D中的内存管理

Unity 3D中的内存管理

unity3d 资源加载与释放的内存管理

如何增加内存来处理超大 Lua 表

操作系统基本组成--内存管理

Linux内存管理机制