为什么分配数组后的堆如此之大?
Why is the heap after array allocation so large
我有一个非常基本的应用程序,可以归结为以下代码:
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);
}
- 为什么堆栈和堆在内存中分离得如此之多?
- 为什么 Lisp 中 1000 阶乘的计算如此之快(并显示正确的结果)?
- 为什么C++线程/未来开销如此之大
- 为什么"quick sorting"算法的这两种变体在性能上差异如此之大?
- 为什么整数的垃圾价值如此之大
- Python vs CPP:为什么速度差异如此之大
- C++-为什么标记化器从文件中读取行的速度如此之慢
- 如何确定为什么我的库中的文本大小如此之大
- 为什么在使用std::bind和lambda时生成的对象如此之大
- 使用 sprintf 分配给字符数组并将字符指针作为输入之一时缓冲区溢出
- 为什么从内存映射文件中读取速度如此之快
- 为什么我的C++程序在从长double切换到float128时速度如此之慢
- 分而治之真的能战胜增加的内存分配吗
- 为什么可执行文件在使用静态库编译后会增长如此之多
- 为什么ucontext的开销如此之高
- 为什么C++堆分配与 Java 的堆分配相比如此慢?
- 在OpenMP中,c++动态内存分配较慢,即使对于代码的非并行部分也是如此
- 为什么分配数组后的堆如此之大?
- Win32 resource.hpp为什么资源ID如此之高
- 如何找出为什么我的DLL增长如此之快