gcc malloc/free的质疑

网上有些帖子说关于malloc/free实现的细节,证实后发现不是那么回事。

这篇帖子前提是看过网上那篇关于说malloc实现的帖子:

http://blog.csdn.net/hzhzh007/article/details/6424638

 

 

首先那些帖子的说法是申请的每块内存前,都有一个mem_control_block结构:

struct mem_control_block

{

  int is_available;  //这块内存是否可用

  int size;      //这块内存的size;

};

 

我按照上面的说法,测试了一下:

#include<stdio.h>

#include<unistd.h>

#include<stdlib.h>

#include<malloc.h>

 

int main()

{

  int* start=sbrk(0);//在没有任何动态分配内存之前,取得堆的最低点,当然这时也是最高点

  printf("the start of heap :%p\n",start);

  int* ptr1=(int*)malloc(12);//申请一块12字节的内存

  printf("the return val of malloc(12): %p\n",ptr1);

  printf("and the end of heap now : %p\n",sbrk(0));//显示在动态分配内存后堆的最高点

  for(int i=0;i<3;i++)

    ptr1[i]=i+1;//让我们实际分配到的内存里面填充数据

  int* ptr2=start;

  for(int i=0;i<10;i++)

  {

    printf("%p:%x",ptr2,*ptr2);//看看堆里面都有些什么

    ptr2++;

  }

  free(ptr1);//释放掉内存

  ptr2=start;

  for(int i=0;i<10;i++)

  {

    printf("%p:%x",ptr2,*ptr2);//看看堆里面还都有些什么

    ptr2++;

  }

  return 0;

}

 

然后编译:

运行:

确实malloc返回后的指针前面有两个int大小的内存,按照帖子的说法,第一存的是is_available,就是截图中的0x8b74000,但是我们free后其值还是0,第二个存的是内存块的大小,这里用的是十六进制表示的,11就是17而这里加上该int的四字节,是16字节,所以size里面存放的不是size 而是size+1。具体有没有这个is_available字段呢?我看我接下来的第二段代码,改了一下(红色部分):

int main()

{

  int* start=sbrk(0);//在没有任何动态分配内存之前,取得堆的最低点,当然这时也是最高点

  printf("the start of heap :%p\n",start);

  int* ptr1=(int*)malloc(12);//申请一块12字节的内存

  int* ptr3=(int*)malloc(12);//附加的,我们再申请一块内存

  int* ptr4=(int*)malloc(12);//附加的,我们申请第三块内存

  printf("the return val of malloc(12): %p\n",ptr1);

  printf("and the end of heap now : %p\n",sbrk(0));//显示在动态分配内存后堆的最高点

  for(int i=0;i<3;i++)

    ptr1[i]=i+1;//让我们实际分配到的内存里面填充数据

  for(int i=0;i<3;i++)

    ptr3[i]=i+1;//让我们实际分配到的内存里面填充数据

  for(int i=0;i<3;i++)

    ptr4[i]=i+1;//让我们实际分配到的内存里面填充数据

  int* ptr2=start;

  for(int i=0;i<20;i++)//将10改为20了

  {

    printf("%p:%x",ptr2,*ptr2);//看看堆里面都有些什么

    ptr2++;

  }

  free(ptr1);//释放掉内存

  free(ptr3);

  free(ptr4);

  ptr2=start;

  for(int i=0;i<20;i++)//将10改为20了

  {

    printf("%p:%x",ptr2,*ptr2);//看看堆里面还都有些什么

    ptr2++;

  }

  return 0;

}

 

然后编译运行 结果:

可以看到除了堆最开始的地方有那么一个4字节里面存的是0,接下来的每次malloc内存后面根本就没有有这个is-avaliable字段,没有这个4字节。

 

因此可以得出一个结论真实的malloc实现并不是那么回事,可能没有那个mem_control_block 结构,或者说至少,mem_control_block里面没有is_available 字段。还有一点,size里面存放的不是size 也不是size+4,更不是size+8,而是,size+4+1(假设sizeof(int)=4)。

虽然我在这儿只展示了两端代码,说明性不是很强,但是我其实做过很多个试验得出了在下面一些结论,可能表述有误,供大家参考,可以去验证(基于linux上的gcc,vc上的话,情况可能不同):

1.堆的最低点的4字节(一个int)永远是0,不是is_available.

 

2.当我上面的代码里面的malloc(12)换成malloc(16),时,你会惊奇的发现,每个malloc 出来的内存块的大小会是24,即size段存的是25,这样就比我们预计的16+4又多了4字节,而这个4字节,又刚好在size段的前面,难道是is_available?告诉你,不是,那是内存对齐空出来的,而且,内存对齐时空出来的大小也算在size字段里面,但是一般我们用sizeof时,返回值不会有内存对齐的考虑,这也是delete和delete[]不能混用的原因之一吧。


3.内存对齐可不止只有类或者结构体里面的内存对其,就是我们自己动手分配的内存(比如上面的ptr1,ptr3,ptr4)之间,也会有内存对其,不同平台可能不同,但linux下gcc编译出来的当分配的内存是用8来对齐的,考虑到size字段。但是当在结构体或者类里面考虑对齐时,由于没有size字段,是用4来对齐的,而在VC下面,是用最大的那个元素的大小来对齐的,就对其策略来说,gcc比vc更好些。

 

4.对于上面运行的结果,有几个值很特殊,我列下来

a)这里的20fd1是当前字节到堆最顶端的距离。该字节后面都是已经被系统映射,但是还没被进程分配的内存。

b)第一个 malloc出来的内存的第一个int位置在free后被改为0,但是接下来的后面几个字节却没有改

c)第二个 malloc出来的内存的第一个int位置在free后被改为0x8938000。

d)第三个malloc出来的内存的第一个int位置在free后被改为0x8938010.

 

为什么free后要改掉内存块的头一个4字节(即size后面的一个4字节)。而且,刚好被改为上一个内存块的起始地址。猜想是为了在内存管理时能够像前遍历。

至于那个is_available 到底在哪儿,那就要看真正的malloc的源码了。

 


就写这么多吧,第一次发帖,没经验,结构很乱,希望大家看了不要很恼火,同时希望大家指出我的错误。

转载于:https://www.cnblogs.com/hamzah/archive/2012/09/28/Zieson.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值