大型二维静态数组和向量向量的内存使用

问题描述 投票:1回答:2

我需要使用大型矩阵20000 * 20000进行机器学习项目。当它作为静态数组实现时,它使用大约1.57 GB的内存。如果使用向量向量实现它,则使用比静态数组(大约3.06 GB)更多的内存。我无法弄清楚背后的原因。

阵列版本:

static double distanceMatrix[20000][20000] = {0};

矢量矢量:

vector<vector<double>> distanceMatrix(20000, vector<double> (20000));

我用它们来存储点之间的距离。

for (int i = 0; i < 20000; i++){
    for (int j = i+1; j < 20000; j++)
        distanceMatrix[i][j] = euclid_dist(pointVec[i], pointVec[j]);
}

我还观察到,当我使用数组版本时,内存使用量在嵌套循环期间逐渐增加。但是,在使用向量向量时,内存使用量达到3.06 GB,然后嵌套循环开始。

我用Xcode调试导航器和Activity Monitor检查了内存使用情况。提前致谢!

c++ arrays xcode memory vector
2个回答
1
投票

首先,阵列不占用1,57 GB的内存。因此测量存在问题。

Experiment with the static array

在Xcode中运行以下代码时,您会发现该数组的大小正好为3,2 Gb:

const size_t matsize=20000;
static double mat2D[matsize][matsize] = {0};  
cout<<"Double:             " << sizeof (double) <<endl;
cout<<"Array:              " << sizeof mat2D <<endl;
cout<<"                    " << sizeof(double)*matsize*matsize<<endl;
// ... then your loop

程序启动时,在进入循环之前报告的内存消耗仅为5,3MB,尽管静态数组已经存在。循环结束后,报告的内存消耗量为1,57 Gb。但仍然不是我们可以期待的3,2Gb。

您读取的内存消耗数字是进程使用的物理内存。进程的剩余内存位于虚拟内存中,这个内存要大得多(在我的实验中为7 Gb)。

载体的实验

首先,让我们看看向量的近似内存大小,知道每个向量具有固定大小加上动态分配的变量大小(基于容量可以等于或大于实际存储在向量中的元素数)。以下代码可以为您提供一些估算:

vector<vector<double>> mat2D(matsize, vector<double> (matsize));
cout<<"Vector (fixed part):" << sizeof (vector<double>)<<endl;
cout<<"Vector capacity:   " << mat2D[0].capacity()<<endl;
cout<<"       (variable):  " << sizeof(double)*mat2D[0].capacity()<<endl;
cout<<"       (total):     " << sizeof(double)*mat2D[0].capacity() + sizeof(mat2D[0])<<endl;
cout<<"Vector of vector:   " << (sizeof(double)*mat2D[0].capacity() + sizeof(mat2D[0]))*matsize+sizeof(mat2D)<<endl;
// then your loop 

运行此代码将显示存储向量向量所需的内存大约为3 Gb + 480 Kb开销(每个向量24个字节* 2001向量)。

在进入循环之前,我们会注意到已经使用了3 Gb的物理内存。因此,与阵列版本相比,MacOS使用的物理内存是此动态版本的两倍。这当然是因为分配过程需要预先真正访问更多内存:2000行中的每一行都需要单独的分配和初始化。

结论

两种方法中使用的整体虚拟内存没有那么不同。我可以使用Xcode在调试模式下测量大约7Gb。由于向量的额外480Kb开销,向量变体比以前使用了一点点。

macOS使用或多或少使用物理内存的策略很复杂,可能取决于许多因素(包括访问模式),目标是找到可用物理内存和交换成本之间的最佳权衡。

但物理内存使用量并不代表进程的内存消耗。


2
投票

这是因为vector的内存分配策略,当达到其限制(依赖于实现)时可能是newsize = oldsize * const,另请参阅vector memory allocation strategy

© www.soinside.com 2019 - 2024. All rights reserved.