一旦我写了一个应用程序,我认为由于索引,我可以方便地使用三维动态分配的数组。但是我无法使用它,因为它比我预期的需要更多的内存。请有人解释一下这背后的算法是什么。为什么在下面的例子中var2需要大约。 640 MB内存不是256 MB。在Dev-C ++ 5.11 64位
中测试#include <iostream>
#include <conio.h>
#include <windows.h>
int main(void)
{
using namespace std ;
MEMORYSTATUS memInfo ;
memInfo.dwLength = sizeof(memInfo) ;
unsigned char *var0 ;
unsigned char **var1 ;
unsigned char ***var2 ;
GlobalMemoryStatus(&memInfo) ;
cout << "Free memory:\t" << (memInfo.dwAvailPhys / 1024 / 1024) << " MB" << endl ;
var0 = new unsigned char[1024 * 1024 * 256] ;
for(int aa = 0; aa < 1024 * 1024 * 256; aa++)
var0[aa] = 0x00 ;
GlobalMemoryStatus(&memInfo) ;
cout << "Free memory:\t" << (memInfo.dwAvailPhys / 1024 / 1024) << " MB" << endl ;
delete[] var0 ;
cout << endl ;
GlobalMemoryStatus(&memInfo) ;
cout << "Free memory:\t" << (memInfo.dwAvailPhys / 1024 / 1024) << " MB" << endl ;
var1 = new unsigned char*[128 * 1024] ;
for(int aa = 0; aa < 128 * 1024; aa++)
var1[aa] = new unsigned char[1024] ;
for(int aa = 0; aa < 128 * 1024; aa++)
for(int bb = 0; bb < 1024; bb++)
var1[aa][bb] = 0x00 ;
GlobalMemoryStatus(&memInfo) ;
cout << "Free memory:\t" << (memInfo.dwAvailPhys / 1024 / 1024) << " MB" << endl ;
delete[] var1 ;
cout << endl ;
GlobalMemoryStatus(&memInfo) ;
cout << "Free memory:\t" << (memInfo.dwAvailPhys / 1024 / 1024) << " MB" << endl ;
var2 = new unsigned char**[16 * 1024] ;
for(int aa = 0; aa < 16 * 1024; aa++)
var2[aa] = new unsigned char*[1024] ;
for(int aa = 0; aa < 16 * 1024; aa++)
for(int bb = 0; bb < 1024; bb++)
var2[aa][bb] = new unsigned char[16] ;
for(int aa = 0; aa < 16 * 1024; aa++)
for(int bb = 0; bb < 1024; bb++)
for(int cc = 0; cc < 16; cc++)
var2[aa][bb][cc] = 0x00 ;
GlobalMemoryStatus(&memInfo) ;
cout << "Free memory:\t" << (memInfo.dwAvailPhys / 1024 / 1024) << " MB" << endl ;
// Why does var2 takes approx. 640 MB of memory ?. 16 *1024 * 1024 * 16 = 256 MB
cout << "\nPress a key to exit." << endl ;
getch() ;
return 0 ;
}
答案 0 :(得分:1)
有两个问题,一个是内存管理器开销。您正在分配大量小块。另一个是指针的大小。
var2 = new unsigned char ** [16 * 1024];
这会分配一块足以存储16x1024指针的内存块。您说您使用的是64位编译器,因此每个指针都是8个字节。所以这分配了一个128千字节的块。这是可以忽略的,我们不会进一步考虑它。
for(int aa = 0; aa&lt; 16 * 1024; aa ++) var2 [aa] =新的无符号字符* [1024];
这会分配16384个块,每块大到足以容纳1024个指针。所以每个块的大小为8千字节。总计128兆字节。
for(int aa = 0; aa&lt; 16 * 1024; aa ++) for(int bb = 0; bb&lt; 1024; bb ++) var2 [aa] [bb] =新的unsigned char [16];
这将分配16777216个块,每个块大小为16个字节。总共256兆字节。
因此,如果内存管理器的开销为零,那么您将分配大约384 MB。所以我们还有256兆字节需要考虑。
当内存管理器分配块时,存储有关分配的元数据的开销。究竟多少取决于内存管理器的实现。在你的情况下,内存管理器看起来每个分配有16个字节(相当于2个指针)的开销。
所以现在我们知道我们可以对它们做些什么?
我们可以通过在更大的块中分配内存并进行一些指针运算来消除大部分内存管理器开销。
size_t dim1 = 16 * 1024;
size_t dim2 = 1024;
size_t dim3 = 16;
var2 = new unsigned char**[dim1] ;
unsigned char ** tmpa = new unsigned char*[dim1*dim2] ;
for(int aa = 0; aa < dim1; aa++) {
var2[aa] = tmpa;
tmpa += dim2;
}
unsigned char * tmpb = new unsigned char[dim1*dim2*dim3];
for(int aa = 0; aa < dim1; aa++) {
for(int bb = 0; bb < 1024; bb++) {
var2[aa][bb] = tmpb;
tmpb += dim3;
}
}
从指针中减少开销很少。如果您对尺寸的相对尺寸有所了解,可以选择一种方法,即重塑您的阵列设计,使最后一个尺寸不会那么小。