为什么分配数组后的堆如此之大?

Why is the heap after array allocation so large

本文关键字:如此之 分配 数组 为什么      更新时间:2023-10-16

我有一个非常基本的应用程序,可以归结为以下代码:

char* gBigArray[200][200][200];
unsigned int Initialise(){  
    for(int ta=0;ta<200;ta++)
        for(int tb=0;tb<200;tb++)
            for(int tc=0;tc<200;tc++)
                gBigArray[ta][tb][tc]=new char;
    return sizeof(gBigArray);
}

函数返回32000000字节的期望值,大约是30MB,但在Windows任务管理器中(并授予它不是100%准确)给出内存(私有工作集)值约为157MB。我已经通过SysInternals将应用程序加载到VMMap中,并具有以下值:

我不确定图像意味着什么(在类型下列出),尽管它的值与我所期望的无关。真正让我感到困惑的是Heap的值,这就是明显的巨大大小的来源。

我不明白的是为什么会这样?根据这个答案,如果我理解正确,gBigArray将被放置在数据或bss段-但我猜,因为每个元素是一个未初始化的指针,它将被放置在bss段。那么为什么堆值会比所需的值大得多呢?

如果您知道内存分配器是如何工作的,那么这听起来并不愚蠢。它们跟踪分配的块,所以有一个存储大小的字段,还有一个指向下一个块的指针,甚至可能有一些填充。一些编译器在调试构建时在分配的区域周围放置保护空间,因此如果您在分配的区域之外或之前写入,当您试图释放分配的空间时,程序可以在运行时检测到它。

一次分配一个字符。每次分配通常有空间开销

在一个大块上分配内存(或至少在几个块上)

不要忘记char* gBigArray[200][200][200];200*200*200=8000000的指针分配了每个字大小的空间。这在32位系统上是32mb。

添加另一个8000000 char到另一个8MB。因为你是一个一个地分配它们,它可能不能以每个项目一个字节的方式分配它们,所以它们可能也会按每个项目的字长分配,从而产生另一个32MB(32位系统)。

其余的可能是开销,这也很重要,因为c++系统必须记住用new分配的数组包含了多少个delete []的元素。

哇!如果面对这些代码,我的嵌入式系统会翻个底朝天。每次分配都有相当多的额外信息与之相关,并且要么间隔为固定大小,要么通过链表类型对象进行管理。在我的系统上,1个新字符将从一个小对象分配器中变成64字节的分配,这样管理将在O(1)时间内完成。但在其他系统中,这可能很容易将内存分割成可怕的碎片,使后续的新建和删除运行得非常慢(O(n),其中n是它跟踪的东西的数量),并且随着时间的推移,通常会给应用程序带来厄运,因为每个字符将成为至少32字节的分配,并被放置在内存的各种小洞中,从而将分配堆推向比您预期的更远的地方。

做一个大的分配,并映射你的3D数组在它上面,如果你需要新的位置或其他指针技巧。

一次分配1个字符可能更昂贵。每次分配都有元数据头,所以一个字符的1字节比头元数据要小,所以你可以通过做一个大的分配来节省空间(如果可能的话),这样你就可以减轻每个分配都有自己的元数据的开销。

也许这是内存跨步的问题?值之间的差距有多大?

30mb用于指针。其余部分是使用new调用分配的存储,指针将指向。由于各种原因,编译器可以分配多个字节,比如对齐字边界,或者为以后需要提供一些增长空间。如果您想要8mb的字符,请将*gBigArray的声明中去掉。

将上述帖子编辑为社区wiki帖子:

正如下面的答案所说,这里的问题是我创建了一个新char 200^3次,尽管每个char只有1个字节,但堆上的每个对象都有开销。似乎为所有字符创建一个字符数组将内存降低到一个更可信的水平:

char* gBigArray[200][200][200];
char* gCharBlock=new char[200*200*200];
unsigned int Initialise(){  
    unsigned int mIndex=0;
    for(int ta=0;ta<200;ta++)
        for(int tb=0;tb<200;tb++)
            for(int tc=0;tc<200;tc++)
                gBigArray[ta][tb][tc]=&gCharBlock[mIndex++];
    return sizeof(gBigArray);
}