网上有些帖子说关于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

gcc malloc/free的质疑相关推荐

  1. LINUX下,C语言MALLOC可能达到的最大空间测试

    一直不怎么用malloc,但是知道malloc申请的是虚拟地址空间.刚好自己的机器是64位的,所以写了个程序做个测试. 代码原理很简单,建立链表,将申请到的空间都存起来.申请到最大之后,再逐一进行释放 ...

  2. Linux NUMA 架构 :基础软件工程师需要知道一些知识

    文章目录 前言 从物理CPU.core到HT(hyper-threading) UMA(Uniform memory access) NUMA架构 NUMA下的内存分配策略 1. MPOL_DEFAU ...

  3. 你确定你理解内存分配吗?

    内存是计算机中必不可少的资源,因为 CPU 只能直接读取内存中的数据,所以当 CPU 需要读取外部设备(如硬盘)的数据时,必须先把数据加载到内存中. 内存是计算机中必不可少的资源,因为 CPU 只能直 ...

  4. 你真的理解内存分配吗?

    内存是计算机中必不可少的资源,因为 CPU 只能直接读取内存中的数据,所以当 CPU 需要读取外部设备(如硬盘)的数据时,必须先把数据加载到内存中. 我们来看看可爱的内存长什么样子的吧,如图1所示: ...

  5. linux 内存 virt,Linux 内存 virt res shr data swap 意义

    virt  res shr data 这几个很容易搞混了,写一下 首先解释下含义: virt : 程序占用的虚拟内存 man: The total amount of virtual memory u ...

  6. gcc -Wl,--wrap,malloc 替换系统函数

    GNU链接器就提供了一个好用的方法: –wrap=symbol 函数名为"__wrap_symbol",且称其为包装函数,"symbol"是一个函数名,大致执行 ...

  7. linux malloc错误,如何规避GCC中“尝试使用中毒的malloc / calloc”错误?

    我正在使用交叉musl编译器(相同版本)构建本机musl编译器(GCC 8.3.0),我收到此错误: In file included from /usr/local/x86_64-cros-linu ...

  8. arm32 linux 内存分布,gcc代码反汇编查看内存分布[2]: arm-linux-gcc

    arm-none-linux-gnueabi-gcc -v gcc version 4.4.1 (Sourcery G++ Lite 2010q1-202) 重点: 代码中的内存分配, 地址从低到高: ...

  9. malloc(0)-malloc 0 字节

    C17中有如下描述: 7.22.3 Memory management functions 1 The order and contiguity of storage allocated by suc ...

最新文章

  1. Flutter事件与手势识别
  2. python3 遍历列表list 四种方法
  3. Android中SharedPreferences与Editor的使用
  4. 【信息抽取】介绍一种端到端的关系抽取方法
  5. QML提供的JavaScript主机环境
  6. Elastic发布K8s部署和控制数据管理工具官方解决方案
  7. linux 查看 CPU 使用率
  8. 介绍全新的 JSX 转换
  9. 计算机java语言答案,2019年全国计算机二级Java语言练习试题及答案一
  10. java的语法基础_JAVA语法基础1(入门手册)
  11. easyexcel 工具类_阿里程序员常用的 15 款开发者工具~
  12. java 存储多叉树_JAVA多叉树森林的构造、内存存储与遍历
  13. 64马8赛道取前4问题
  14. android 7双排设置菜单,双排状态栏布局教程
  15. MySQL——连接查询
  16. python英文翻译-python中英文翻译
  17. 父子或兄弟div元素边距重叠
  18. UC研发团队热招中!(12月20日更新版)
  19. 幼儿园计算机课件制作评比表,幼儿园课件制作基本原则与评价标准_表格评价.doc...
  20. input取消焦点 vue_vue如何能做到点击其他地方input不失去焦点

热门文章

  1. ActiveMQ 依赖JDK版本
  2. ORACLE 索引的三种状态: VALID、 N/A 、UNUSABLE
  3. Vue中watch的使用
  4. Android开发笔记(一百三十七)自定义行为Behavior
  5. 分治比赛选手循环问题
  6. jq中html(),text(),val()以及js中innerHTML,innerText和value
  7. centos杀死进程命令
  8. .NET PPT控件 Spire.Presentation for .NET V2.8发布 | 附下载
  9. 新技能,利用Reflector来修改dll引用
  10. 常见的mysql集群