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
gcc malloc/free的质疑相关推荐
- LINUX下,C语言MALLOC可能达到的最大空间测试
一直不怎么用malloc,但是知道malloc申请的是虚拟地址空间.刚好自己的机器是64位的,所以写了个程序做个测试. 代码原理很简单,建立链表,将申请到的空间都存起来.申请到最大之后,再逐一进行释放 ...
- Linux NUMA 架构 :基础软件工程师需要知道一些知识
文章目录 前言 从物理CPU.core到HT(hyper-threading) UMA(Uniform memory access) NUMA架构 NUMA下的内存分配策略 1. MPOL_DEFAU ...
- 你确定你理解内存分配吗?
内存是计算机中必不可少的资源,因为 CPU 只能直接读取内存中的数据,所以当 CPU 需要读取外部设备(如硬盘)的数据时,必须先把数据加载到内存中. 内存是计算机中必不可少的资源,因为 CPU 只能直 ...
- 你真的理解内存分配吗?
内存是计算机中必不可少的资源,因为 CPU 只能直接读取内存中的数据,所以当 CPU 需要读取外部设备(如硬盘)的数据时,必须先把数据加载到内存中. 我们来看看可爱的内存长什么样子的吧,如图1所示: ...
- linux 内存 virt,Linux 内存 virt res shr data swap 意义
virt res shr data 这几个很容易搞混了,写一下 首先解释下含义: virt : 程序占用的虚拟内存 man: The total amount of virtual memory u ...
- gcc -Wl,--wrap,malloc 替换系统函数
GNU链接器就提供了一个好用的方法: –wrap=symbol 函数名为"__wrap_symbol",且称其为包装函数,"symbol"是一个函数名,大致执行 ...
- linux malloc错误,如何规避GCC中“尝试使用中毒的malloc / calloc”错误?
我正在使用交叉musl编译器(相同版本)构建本机musl编译器(GCC 8.3.0),我收到此错误: In file included from /usr/local/x86_64-cros-linu ...
- arm32 linux 内存分布,gcc代码反汇编查看内存分布[2]: arm-linux-gcc
arm-none-linux-gnueabi-gcc -v gcc version 4.4.1 (Sourcery G++ Lite 2010q1-202) 重点: 代码中的内存分配, 地址从低到高: ...
- malloc(0)-malloc 0 字节
C17中有如下描述: 7.22.3 Memory management functions 1 The order and contiguity of storage allocated by suc ...
最新文章
- Flutter事件与手势识别
- python3 遍历列表list 四种方法
- Android中SharedPreferences与Editor的使用
- 【信息抽取】介绍一种端到端的关系抽取方法
- QML提供的JavaScript主机环境
- Elastic发布K8s部署和控制数据管理工具官方解决方案
- linux 查看 CPU 使用率
- 介绍全新的 JSX 转换
- 计算机java语言答案,2019年全国计算机二级Java语言练习试题及答案一
- java的语法基础_JAVA语法基础1(入门手册)
- easyexcel 工具类_阿里程序员常用的 15 款开发者工具~
- java 存储多叉树_JAVA多叉树森林的构造、内存存储与遍历
- 64马8赛道取前4问题
- android 7双排设置菜单,双排状态栏布局教程
- MySQL——连接查询
- python英文翻译-python中英文翻译
- 父子或兄弟div元素边距重叠
- UC研发团队热招中!(12月20日更新版)
- 幼儿园计算机课件制作评比表,幼儿园课件制作基本原则与评价标准_表格评价.doc...
- input取消焦点 vue_vue如何能做到点击其他地方input不失去焦点
热门文章
- ActiveMQ 依赖JDK版本
- ORACLE 索引的三种状态: VALID、 N/A 、UNUSABLE
- Vue中watch的使用
- Android开发笔记(一百三十七)自定义行为Behavior
- 分治比赛选手循环问题
- jq中html(),text(),val()以及js中innerHTML,innerText和value
- centos杀死进程命令
- .NET PPT控件 Spire.Presentation for .NET V2.8发布 | 附下载
- 新技能,利用Reflector来修改dll引用
- 常见的mysql集群