多维数组动态内存分配背后的算法是啥?

Posted

技术标签:

【中文标题】多维数组动态内存分配背后的算法是啥?【英文标题】:What's the arithmetic behind dynamic memory allocation with multidimentional arrays?多维数组动态内存分配背后的算法是什么? 【发布时间】:2016-02-07 02:57:19 【问题描述】:

在编写应用程序时,我认为使用 3 维动态分配的数组会很方便,因为有索引。但是我无法使用它,因为它占用的内存比我预期的要多。请有人解释一下这背后的算术是什么。为什么在下面的示例中 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 ;

【问题讨论】:

我不知道这是否重要 - 我正在运行 Windows Server 2008 R2 【参考方案1】:

有两个问题,一个是内存管理器开销。您正在分配大量小块。另一个是指针的大小。

var2 = 新的无符号字符**[16 * 1024] ;

这会分配一块足够大的内存来存储 16x1024 个指针。您说您使用的是 64 位编译器,因此每个指针是 8 个字节。所以这分配了一个 128 KB 的块。这可以忽略不计,我们不会进一步考虑。

for(int aa = 0;aa

这分配了 16384 个块,每个块都足够容纳 1024 个指针。所以每个块的大小为 8 KB。总共 128 兆字节。

for(int aa = 0;aa

这会分配 16777216 个大小为 16 字节的块。总共 256 兆字节。

因此,如果内存管理器的开销为零,您将分配大约 384 兆字节。所以我们还有 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;
  

减少指针的开销是比较棘手的。如果您事先对维度的相对大小有所了解,一个选择可能是重塑您的阵列设计,以使最后一个维度不那么小。

【讨论】:

好的。我想知道如何计算这个过度的大小。只是好奇 看起来你刚刚计算过了。 无论如何,这不仅仅是内存管理器的开销......你忘记了所有这些指针的大小! 我不知道。如果我不能检查函数调用,我就不知道如何自己计算。我认为有时需要知道将使用多少内存 这就是我一直在寻找的答案

以上是关于多维数组动态内存分配背后的算法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

内存堆问题 C++,动态分配多维数组

“动态分配的内存模拟多维数组”的正确术语?

如何分配动态静态多维数组

数据结构与算法基础之malloc()动态分配内存概述

删除动态分配的内存的最佳做法是啥?

动态内存使用速度较慢是啥? [复制]