我需要使用大型矩阵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检查了内存使用情况。提前致谢!
首先,阵列不占用1,57 GB的内存。因此测量存在问题。
在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使用或多或少使用物理内存的策略很复杂,可能取决于许多因素(包括访问模式),目标是找到可用物理内存和交换成本之间的最佳权衡。
但物理内存使用量并不代表进程的内存消耗。
这是因为vector
的内存分配策略,当达到其限制(依赖于实现)时可能是newsize = oldsize * const,另请参阅vector memory allocation strategy