首页 新闻 会员 周边

C++ 堆内存分配不解问题

0
悬赏园豆:10 [已解决问题] 解决于 2014-05-23 16:51

栈上内存没什么,是多少就是多少。

可是在堆上内存分配的时候,就奇怪了。。

你们有没有试验过,new char[12]然后打开windows内存管理器占用的KB或者M,发现会比你想象的12个要多出来一些,然后我就一直试,最后发现new char[16]和12 分配的内存是一样的。

最终经过很多次测试总结出来了内存分配的规律,就是代码中我们看到的要分配的内存比如是K,windows会把K向上去8的整数倍(如:8 16 24)然后再加上一个8才是真正的Byte,然后这个数/1024才是真正内存管理器中显示出来的真正占用Kb。。

以上,有测试过的,懂的朋友给解释下,向上取8整的倍,可以理解是为了一定程度上避免内存碎片,那么 ,多出来的那个8Byte是放的什么呢?

yikoda的主页 yikoda | 初学一级 | 园豆:95
提问于:2014-05-11 12:11
< >
分享
最佳答案
0
运行这样一段代码做个实验:
char *p = 0; for(int i = 0; i < 40; i += 4) {    char* s = new char[i];    printf("alloc %2d bytes, address=%p distance=%d/n", i, s, s - p);    p = s; }
我们直接来看VC2005下Release版本的运行结果,DEBUG版因包含了较多的调试信息,这里就不分析了:
alloc 0 bytes, address=003A36F0 distance=3815152
alloc 4 bytes, address=003A3700 distance=16
alloc 8 bytes, address=003A3710 distance=16
alloc 12 bytes, address=003A3720 distance=16
alloc 16 bytes, address=003A3738 distance=24
alloc 20 bytes, address=003A84C0 distance=19848
alloc 24 bytes, address=003A84E0 distance=32
alloc 28 bytes, address=003A8500 distance=32
alloc 32 bytes, address=003A8528 distance=40
alloc 36 bytes, address=003A8550 distance=40
每一次分配的字节数都比上一次多4,distance值记录着与上一次分配的差值,第一个差值没有实际意义,中间有一个较大的差值,可能是这块内存已经被分配了,于是也忽略它。结果中最小的差值为16字节,直到我们申请16字节时,这个差值变成了24,后面也有类似的规律,那么我们可以认为申请所得的内存结构是如下这样的:
从图中不难看出,当我们要分配一段内存时,所得的内存地址和上一次的尾地址至少要相距8个字节(在DEBUG版中还要更多),那么我们可以猜想,这8个字节中应该记录着与这段所分配的内存有关的信息。观察这8个节内的内容,得到结果如下:
图中右边为每次分配所得的地址之前8个字节的内容的16进制表示,从图中红线所表示可以看到,这8个字节中的第一个字节乘以8即得到相临两次分配时的距离,经过试验一次性分配更大的长度可知,第二个字节也是这个意义,并且代表高8位,也就说前面空的这8个字节中的前两个字节记录了一次分配内存的长度信息,后面的六个字节可能与空闲内存链表的信息有关,在翻译内存时用来提供必要的信息。这就解答了前面提出的问题,原来C/C++在分配内存时已经记录了足够充分的信息用于回收内存,只不过我们平常不关心它罢了。
收获园豆:10
rlandj | 菜鸟二级 |园豆:212 | 2014-05-11 13:54

指针是一块地址,然后申请出来的内存在一块地址,我猜测的是这两者之间的联系的一些信息,谢谢楼上的回答,楼上分析问题的方式很赞,可是 也是根据数据推理猜测的,就是不知道有没有一本书上,明确说明过。。其实这个问题,说大不大说小也不小,数据比较大,在内存不太足的时候,这个事情就要考虑的到了。

yikoda | 园豆:95 (初学一级) | 2014-05-11 14:55
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册