有没有蜗居 网盘无删减版百度网盘?广告绕道

关于malloc函数后free内存空间的疑问&
   问题:&
  malloc是开出内存空间。&
  现在我写了这么一句:&
  char *&
  name=(char *)malloc(len*sizeof(char));&
  name指针是个char指针,指向一个char数据,即只保留了一个char数据的长度信息.free的时候它如何知道开出的空间到底有多长?&
  解答:&
  (1)malloc是一个库函数,不是由操作系统提供的,绝大部分都是由编译器提供的库包自己实现的。malloc如何实现,依赖于不同的操作系统跟不同的c库。&
  比如,在linux上面,malloc是调用brk系统调用进行内存分配的,而在windows则是HeapAlloc等等类似的系统函数分配内存。&
  一般c库在初始化的时候都是一下子在堆中分配了一大部分内存,然后再根据自己的算法对这些内存进行分配。至于free怎么知道要free多少字节。其实很简单,因为每用malloc分配一个内存块,c库就要记住你分配的多少字节,一般情况下都是记在返回指针的前几个字节。&
  (2)c库记忆就是开辟额外的空间记录分配内存的大小,开辟额外的空间去记录分配内存的大小也只是一个权宜之计,也只是c库玩的一种把戏而已。微软的c库这么做,gcc的c库这么做,但不代表其他所有编译器的c库都这么做。所以,通俗的讲,或者更一般的讲,用c库记忆更具有一般性。&
  (3)比如char * buf1 = (char*)malloc (32);&&
  那么buf1[-8]~ buf1[-1] 都是用来放管理信息的!特别是在windows下编程是如此.&&
  buf1的管理结构(8bytes)& |& buf1真正可操作空间(32bytes)&& |&&& 下一个空闲堆的管理结构(8bytes)|两个双链表指针(8bytes)&
  ↑ & & & & & & & & & & & & & & & & & & ↑&
  Free()根据这里提供的 & & & & buf1真正指向这里&
  管理信息来回收内存&
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:183711次
积分:2015
积分:2015
排名:第17614名
转载:95篇
评论:18条
(1)(1)(1)(2)(1)(3)(4)(10)(8)(3)(9)(8)(4)(3)(11)(24)(4)(1)(5)关于malloc函数后free内存空间的疑问_C++,C语言_ThinkSAAS
关于malloc函数后free内存空间的疑问
关于malloc函数后free内存空间的疑问
内容来源: 网络
malloc是开出内存空间。
现在我写了这么一句:
name=(char *)malloc(len*sizeof(char));
name指针是个char指针,指向一个char数据,即只保留了一个char数据的长度信息.free的时候它如何知道开出的空间到底有多长?
(1)malloc是一个库函数,不是由操作系统提供的,绝大部分都是由编译器提供的库包自己实现的。malloc如何实现,依赖于不同的操作系统跟不同的c库。
比如,在linux上面,malloc是调用brk系统调用进行内存分配的,而在windows则是HeapAlloc等等类似的系统函数分配内存。
一般c库在初始化的时候都是一下子在堆中分配了一大部分内存,然后再根据自己的算法对这些内存进行分配。至于free怎么知道要free多少字节。其实很简单,因为每用malloc分配一个内存块,c库就要记住你分配的多少字节,一般情况下都是记在返回指针的前几个字节。
(2)c库记忆就是开辟额外的空间记录分配内存的大小,开辟额外的空间去记录分配内存的大小也只是一个权宜之计,也只是c库玩的一种把戏而已。微软的c库这么做,gcc的c库这么做,但不代表其他所有编译器的c库都这么做。所以,通俗的讲,或者更一般的讲,用c库记忆更具有一般性。
(3)比如char * buf1 = (char*)malloc (32);
那么buf1[-8]~ buf1[-1] 都是用来放管理信息的!特别是在windows下编程是如此.
buf1的管理结构(8bytes)
buf1真正可操作空间(32bytes)
下一个空闲堆的管理结构(8bytes)|两个双链表指针(8bytes)
Free()根据这里提供的
buf1真正指向这里
管理信息来回收内存
PHP开发框架
开发工具/编程工具
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
让ThinkSAAS更好,把建议拿来。
开发客服微信获取malloc的内存大小 - 开源中国社区
当前访客身份:游客 [
当前位置:
发布于 日 16时,
可使用该宏获取malloc、realloc分配的内存大小。
代码片段(1)
1.&[代码][C/C++]代码&&&&
#include &stdio.h&
#include &malloc.h&
#define sizeMalloc(p) (*(((unsigned int *)p)-1) & ~(0x01|0x02))
int main(void)
for(i=0; i&30; i++) {
void* p = malloc(i);
printf("malloc %d-%d bytes!\n", i, sizeMalloc(p));
开源中国-程序员在线工具:
内存不是申请多大,就是多大吗?&要么成功,要么失败,有必要再计算一下尺寸吗?
2楼:bbdlg 发表于
引用来自“雲飛揚”的评论
内存不是申请多大,就是多大吗?&要么成功,要么失败,有必要再计算一下尺寸吗?
我是用在同一程序中,模块Amalloc了一块内存,填充了数据,由模块B负责使用这些数据,并负责释放。在使用时,需要知道内存的大小。 但是注意,比如malloc了5个字节的内存,这个宏得到的大小为16。也就是说并不能得到内存的准确大小,因为通过malloc获得的内存是8字节对齐的。
3楼:fys 发表于
引用来自“bbdlg”的评论引用来自“雲飛揚”的评论
内存不是申请多大,就是多大吗?&要么成功,要么失败,有必要再计算一下尺寸吗?
我是用在同一程序中,模块Amalloc了一块内存,填充了数据,由模块B负责使用这些数据,并负责释放。在使用时,需要知道内存的大小。 但是注意,比如malloc了5个字节的内存,这个宏得到的大小为16。也就是说并不能得到内存的准确大小,因为通过malloc获得的内存是8字节对齐的。你是要计算数据占多大内存吧
4楼:bbdlg 发表于
引用来自“雲飛揚”的评论引用来自“bbdlg”的评论引用来自“雲飛揚”的评论
内存不是申请多大,就是多大吗?&要么成功,要么失败,有必要再计算一下尺寸吗?
我是用在同一程序中,模块Amalloc了一块内存,填充了数据,由模块B负责使用这些数据,并负责释放。在使用时,需要知道内存的大小。 但是注意,比如malloc了5个字节的内存,这个宏得到的大小为16。也就是说并不能得到内存的准确大小,因为通过malloc获得的内存是8字节对齐的。你是要计算数据占多大内存吧嗯~
5楼:小魔 发表于
申请一个字符数组不可吗,
6楼:庄金峰 发表于
字节对齐在编译器编译的时候做,如果你没有指定对齐的字节数,默认使用4字节对齐,可能还会做一些其他的优化。你可以打印出地址来看,malloc两次。
7楼:bbdlg 发表于
引用来自“庄金峰”的评论字节对齐在编译器编译的时候做,如果你没有指定对齐的字节数,默认使用4字节对齐,可能还会做一些其他的优化。你可以打印出地址来看,malloc两次。glibc里对malloc的实现木有看过... malloc了两次后,可以两次分配的地址没有是没有规律的。malloc分配的内存信息是记录在一个双向链表内malloc_chunk内的,分配的内存没有规律是合理的。
8楼:bbdlg 发表于
引用来自“小魔”的评论申请一个字符数组不可吗,如果不知道要分配多大嘞:)
9楼:coperator 发表于
#include &stdio.h& #include &malloc.h&
#define sizeMalloc(p) (*(((unsigned int *) p) - 1) & (0x01|0x02))
int main(void) { && &int i = 0; && &for(i = 0; i & 100; i ++) && &{ && &&& &void *p = malloc(i); && &&& &printf(&\tmalloc %d-%d bytes! %u\t&, i, sizeMalloc(p),p); && &&& &free(p); && &} && &return 0; }
能帮忙解释下么?为什么会有的是5个值相等,有的是16个值相等
10楼:bbdlg 发表于
引用来自“coperator”的评论 #include &stdio.h& #include &malloc.h&
#define sizeMalloc(p) (*(((unsigned int *) p) - 1) & (0x01|0x02))
int main(void) { && &int i = 0; && &for(i = 0; i & 100; i ++) && &{ && &&& &void *p = malloc(i); && &&& &printf(&\tmalloc %d-%d bytes! %u\t&, i, sizeMalloc(p),p); && &&& &free(p); && &} && &return 0; }
能帮忙解释下么?为什么会有的是5个值相等,有的是16个值相等
测试了一下你的代码,没有出现你说的现象呢; PS:(0x01|0x02)) 应该是 ~(0x01|0x02))
11楼:zhcosin 发表于
你分配了多少,把参数传过去不就行了?
12楼:zhcosin 发表于
其实最关键的问题是你这样的设计不合理,由模块 A 申请的,就应该由模块 A 来释放,模板 B 只管使用,维护内存的工作不应该由他来完成。
13楼:bbdlg 发表于
引用来自“zhcosin”的评论其实最关键的问题是你这样的设计不合理,由模块 A 申请的,就应该由模块 A 来释放,模板 B 只管使用,维护内存的工作不应该由他来完成。
只是提供一种方法:)
14楼:中山野鬼 发表于
这个我吭一句,没有太多意义。知道了又能怎么样?如果知道分配原理以调整你的程序设计,会导致你的程序设计,隐含了malloc之类系统实现方法的逻辑。而或者根据你的设计去调整malloc的实现?这更对移植性产生了影响。对于malloc的利用,更多有价值的考虑是自身代码逻辑对空间的利用情况,一次性搞齐,自己规划着用。这比琢磨那些碰系统资源的底层库的实现要更有价值。
15楼:七液 发表于
引用来自“雲飛揚”的评论
内存不是申请多大,就是多大吗?&要么成功,要么失败,有必要再计算一下尺寸吗?
内存都是基于块的。就和硬盘一样。磁盘格式都是分块的 加入你的文件是1024字节在NTFS格式下默认你还是占用4096字节
16楼:LFMY 发表于
#include&malloc.h&
17楼:葛世超ChicoGe 发表于
引用来自“中山野鬼”的评论这个我吭一句,没有太多意义。知道了又能怎么样?如果知道分配原理以调整你的程序设计,会导致你的程序设计,隐含了malloc之类系统实现方法的逻辑。而或者根据你的设计去调整malloc的实现?这更对移植性产生了影响。对于malloc的利用,更多有价值的考虑是自身代码逻辑对空间的利用情况,一次性搞齐,自己规划着用。这比琢磨那些碰系统资源的底层库的实现要更有价值。这要看做什么,奇技淫巧和歪门邪道往往被世人所鄙夷,但有些地方如此奇技淫巧却能更胜一筹,保不准LZ就是个猥琐男呢!!
开源从代码分享开始
bbdlg的其它代码1,malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。 2,对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
3,因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。 4,C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。5、new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。一:new delete 是运算符,malloc,free是函数malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
1. malloc()函数 1.1 malloc的全称是memory allocation,中文叫动态内存分配。 原型:extern void *malloc(unsigned int num_bytes);& 说明:分配长度为num_bytes字节的内存块。如果分配成功则返回指向被分配内存的指针,分配失败返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。
1.2 void *malloc(int size);& 说明:malloc 向系统申请分配指定size个字节的内存空间,返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。    备注:void* 表示未确定类型的指针,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者...)
1.3 free void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。
1.4注意事项 1)申请了内存空间后,必须检查是否分配成功。
2)当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。
3)这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。
4)虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。
1.5& malloc()到底从哪里得到了内存空间? 答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
2. new运算符
2.1 C++中,用new和delete动态创建和释放数组或单个对象。 动态创建对象时,只需指定其数据类型,而不必为该对象命名,new表达式返回指向该新创建对象的指针,我们可以通过指针来访问此对象。 int *pi= 这个new表达式在堆区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针pi 。
2.2 动态创建对象的初始化 动态创建的对象可以用初始化变量的方式初始化。 int *pi=new int(100); //指针pi所指向的对象初始化为100 string *ps=new string(10,'9');//*ps 为&&
如果不提供显示初始化,对于类类型,用该类的默认构造函数初始化;而内置类型的对象则无初始化。 也可以对动态创建的对象做值初始化: int *pi=new int( );//初始化为0 int *pi=//pi 指向一个没有初始化的int string *ps=new string( );//初始化为空字符串 (对于提供了默认构造函数的类类型,没有必要对其对象进行值初始化)
2.3 撤销动态创建的对象 delete表达式释放指针指向的地址空间。// 释放单个对象 delete [ ]//释放数组 如果指针指向的不是new分配的内存地址,则使用delete是不合法的。
2.4 在delete之后,重设指针的值
//执行完该语句后,p变成了不确定的指针,在很多机器上,尽管p值没有明确定义,但仍然存放了它之前所指对象的地址,然后p所指向的内存已经被释放了,所以p不再有效。此时,该指针变成了悬垂指针(悬垂指针指向曾经存放对象的内存,但该对象已经不存在了)。悬垂指针往往导致程序错误,而且很难检测出来。 一旦删除了指针所指的对象,立即将指针置为0,这样就非常清楚的指明指针不再指向任何对象。(零值指针:int *ip=0;)
2.5 区分零值指针和NULL指针 零值指针,是值是0的指针,可以是任何一种指针类型,可以是通用变体类型void*也可以是char*,int*等等。 空指针,其实空指针只是一种编程概念,就如一个容器可能有空和非空两种基本状态,而在非空时可能里面存储了一个数值是0,因此空指针是人为认为的指针不提供任何地址讯息。2.6 new分配失败时,返回什么? 1993年前,c++一直要求在内存分配失败时operator&& new要返回0,现在则是要求operator&& new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator&& new(以及operator&& new[])以继续提供返回0功能。这些形式被称为&无抛出&,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象:& class&& widget&& {&& ...&& };
widget&& *pw1&& =&& new&&//&& 分配失败抛出std::bad_alloc&&
if&& (pw1&& ==&& 0)&& ... //&& 这个检查一定失败
widget&& *pw2&& =&& new&& (nothrow)&&&& //&& 若分配失败返回0
if&& (pw2&& ==&& 0)&& ... //&& 这个检查可能会成功
3. malloc和new的区别
3.1 new 返回指定类型的指针,并且可以自动计算所需要大小。 比如:    1)&int *p;    p = //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int);    或:    int*    parr = new int [100]; //返回类型为 int* 类型(整数型指针),分配大小为 sizeof(int) * 100;   
2)&而 malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。    int*    p = (int *) malloc (sizeof(int)*128);//分配128个(可根据实际需要替换该数值)整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中&& double *pd=(double *) malloc (sizeof(double)*12);//分配12个double型存储单元,并将首地址存储到指针变量pd中
3.2 malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。 除了分配及最后释放的方法不一样以外,通过malloc或new得到指针,在其它操作上保持一致。
4.有了malloc/free为什么还要new/delete? 1)&malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2)&对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的&对象&没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。
3)&既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。如果用free释放&new创建的动态对象&,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放&malloc申请的动态内存&,结果也会导致程序出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。
阅读(...) 评论()大家应该都比较熟悉这一点:malloc分配的内存一定大于用户指定的大小!而且很多人也问过这样的问题:到底大多少?以及实际上malloc到底分配了多少?
我们知道这个大小一定在某个“神奇”地方记录着,但是就像自己的“思维”一样,你确无法感知!不过,这是错觉,只是我们习惯了只使用,而没有深入剖析源码,在这里我将揭开这个面纱,去掉其透明化!
声明:源码基于GNU glib库的2.7版本的malloc目录下相关文件
再声明:不同的C库实现方式不一定一样,这里是glib库,如果你想知道window的或者其他,请Alt + F4
malloc.c中开篇注释表达一种观点:这里的算法不一定是最好的,但是应该是普遍适用的
此文件包含的函数实现,以及Vital statistics,Alignment,Minimum/Maximum allocated size,最后注明:我是线程安全的,骚年call me!@_@
* Why use this malloc?
This is not the fastest, most space-conserving, most portable, or
most tunable malloc ever written. However it is among the fastest
while also being among the most space-conserving, portable and tunable.
Consistent balance across these factors results in a good general-purpose
allocator for malloc-intensive programs.
The main properties of the algorithms are:
* For large (&= 512 bytes) requests, it is a pure best-fit allocator,
with ties normally decided via FIFO (i.e. least recently used).
* For small (&= 64 bytes by default) requests, it is a caching
allocator, that maintains pools of quickly recycled chunks.
* In between, and for combinations of large and small requests, it does
the best it can trying to meet both goals at once.
* For very large requests (&= KB by default), it relies on system
memory mapping facilities, if supported.
For a longer but slightly out of date high-level description, see
http://gee.cs.oswego.edu/dl/html/malloc.html
You may already by default be using a C library containing a malloc
based on some version of this malloc (for example in
linux). You might still want to use the one in this file in order to
customize settings or to avoid overheads associated with library
* Contents, described in more detail in &description of public routines& below.
Standard (ANSI/SVID/...)
functions:
malloc(size_t n);
calloc(size_t n_elements, size_t element_size);
free(void* p);
realloc(void* p, size_t n);
memalign(size_t alignment, size_t n);
valloc(size_t n);
mallinfo()
mallopt(int parameter_number, int parameter_value)
Additional functions:
independent_calloc(size_t n_elements, size_t size, void* chunks[]);
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
pvalloc(size_t n);
cfree(void* p);
malloc_trim(size_t pad);
malloc_usable_size(void* p);
malloc_stats();
* Vital statistics:
Supported pointer representation:
4 or 8 bytes
Supported size_t
representation:
4 or 8 bytes
Note that size_t is allowed to be 4 bytes even if pointers are 8.
You can adjust this by defining INTERNAL_SIZE_T
Alignment:
2 * sizeof(size_t) (default)
(i.e., 8 byte alignment with 4byte size_t). This suffices for
nearly all current machines and C compilers. However, you can
define MALLOC_ALIGNMENT to be wider than this if necessary.
Minimum overhead per allocated chunk:
4 or 8 bytes
Each malloced chunk has a hidden word of overhead holding size
and status information.
Minimum allocated size: 4-byte ptrs:
(including 4 overhead)
8-byte ptrs:
24/32 bytes (including, 4/8 overhead)
When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
4 (8) for a trailing size field and 8 (16) bytes for
free list pointers. Thus, the minimum allocatable size is
16/24/32 bytes.
Even a request for zero bytes (i.e., malloc(0)) returns a
pointer to something of the minimum allocatable size.
The maximum overhead wastage (i.e., number of extra bytes
allocated than were requested in malloc) is less than or equal
to the minimum size, except for requests &= mmap_threshold that
are serviced via mmap(), where the worst case wastage is 2 *
sizeof(size_t) bytes plus the remainder from a system page (the
minimal mmap unit); typically 96 or 8192 bytes.
Maximum allocated size:
4-byte size_t: 2^32 minus about two pages
8-byte size_t: 2^ minus about two pages
It is assumed that (possibly signed) size_t values suffice to
represent chunk sizes. `Possibly signed' is due to the fact
that `size_t' may be defined on a system as either a signed or
an unsigned type. The ISO C standard says that it must be
unsigned, but a few systems are known not to adhere to this.
Additionally, even when size_t is unsigned, sbrk (which is by
default used to obtain memory from system) accepts signed
arguments, and may not be able to handle size_t-wide arguments
with negative sign bit.
Generally, values that would
appear as negative after accounting for overhead and alignment
are supported only via mmap(), which does not have this
limitation.
Requests for sizes outside the allowed range will perform an optional
failure action and then return null. (Requests may also
also fail because a system is out of memory.)
Thread-safety: thread-safe
malloc的实现
void * __libc_malloc (size_t bytes)
mstate ar_
void *(*hook) (size_t, const void *)
= atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS (0));
arena_get (ar_ptr, bytes);
if (!ar_ptr)
victim = _int_malloc (ar_ptr, bytes);
if (!victim)
LIBC_PROBE (memory_malloc_retry, 1, bytes);
ar_ptr = arena_get_retry (ar_ptr, bytes);
if (__builtin_expect (ar_ptr != NULL, 1))
victim = _int_malloc (ar_ptr, bytes);
(void) mutex_unlock (&ar_ptr-&mutex);
(void) mutex_unlock (&ar_ptr-&mutex);
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
ar_ptr == arena_for_chunk (mem2chunk (victim)));
libc_hidden_def (__libc_malloc)
抛开细节看重点,这个函数只需要注意这两句代码即可,就是这两句
victim = _int_malloc (ar_ptr, bytes);
换言之,__libc_malloc只是一个封装,真正完成分配任务的是函数_int_malloc。
_int_malloc()这函数非常大,上百行的样子,有兴趣的骚年,自己读去哈!
此函数的主要思想就是根据用户申请而指定的大小,做出不同的分配方案;具体怎么分配先不管喽,解决主要问题!——代码无边,重点是岸 ^_^!
其中有四句,一句定义,剩余三句共有的重要的代码
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
victim的数据类型mchunkptr,它是个指针
typedef struct malloc_chunk*结构体struct malloc_chunk定义
struct malloc_chunk {
size_t prev_
/* Size of previous chunk (if free).
/* Size in bytes, including overhead. */
struct malloc_chunk * /* double links -- used only if free. */
struct malloc_chunk *
/* Only used for large blocks: pointer to next larger size.
struct malloc_chunk *fd_ /* double links -- used only if free. */
struct malloc_chunk *bk_
victim是特定分配算法分配的内存地址,其中已经包含分配的大小信息,chunk2mem是个宏; alloc_perturb此函数调用memset初始分配的内存——全部清零!
#define chunk2mem(p)
((void*)((char*)(p) + 2*SIZE_SZ))
其中SIZE_SZ还是个宏,迭代展开就是sizeof(size_t),&size_t大家都熟悉,为什么加两个无符号整型大小呢?
看上面结构体struct malloc_chunk定义?秒懂?跳过的就是prev_size成员和size成员(两个成员的意义:看结构中注释)
此外,在_int_malloc中有这段注释,也很有价值
Convert request size to internal form by adding SIZE_SZ bytes
overhead plus possibly more to obtain necessary alignment and/or
to obtain a size of at least MINSIZE, the smallest allocatable
size. Also, checked_request2size traps (returning 0) request sizes
that are so large that they wrap around zero when padded and
最后,_int_malloc执行返回偏移调整后的p,回到主调函数_lib_malloc中,然后_lib_malloc执行return&victim;——即用户malloc得到的地址。
一目了然,大小的信息就藏在malloc返回地址的前面,即struct malloc_chunk结构体内
结构体其布局
malloc_chunk details:
(The following includes lightly edited explanations by Colin Plumb.)
Chunks of memory are maintained using a `boundary tag' method as
described in e.g., Knuth or Standish.
(See the paper by Paul
Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
survey of such techniques.)
Sizes of free chunks are stored both
in the front of each chunk and at the end.
This makes
consolidating fragmented chunks into bigger chunks very fast.
size fields also hold bits representing whether chunks are free or
An allocated chunk looks like this:
chunk-& +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of previous chunk, if allocated
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of chunk, in bytes
mem-& +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
User data starts here...
(malloc_usable_size() bytes)
nextchunk-& +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of chunk
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Where &chunk& is the front of the chunk for the purpose of most of
the malloc code, but &mem& is the pointer that is returned to the
&Nextchunk& is the beginning of the next contiguous chunk.
Chunks always begin on even word boundaries, so the mem portion
(which is returned to the user) is also on an even word boundary, and
thus at least double-word aligned.
Free chunks are stored in circular doubly-linked lists, and look like this:
chunk-& +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Size of previous chunk
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`head:' |
Size of chunk, in bytes
mem-& +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Forward pointer to next chunk in list
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Back pointer to previous chunk in list
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Unused space (may be 0 bytes long)
nextchunk-& +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
`foot:' |
Size of chunk, in bytes
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The P (PREV_INUSE) bit, stored in the unused low-order bit of the
chunk size (which is always a multiple of two words), is an in-use
bit for the *previous* chunk.
If that bit is *clear*, then the
word before the current chunk size contains the previous chunk
size, and can be used to find the front of the previous chunk.
The very first chunk allocated always has this bit set,
preventing access to non-existent (or non-owned) memory. If
prev_inuse is set for any given chunk, then you CANNOT determine
the size of the previous chunk, and might even get a memory
addressing fault when trying to do so.
Note that the `foot' of the current chunk is actually represented
as the prev_size of the NEXT chunk. This makes it easier to
deal with alignments etc but can be very confusing when trying
to extend or adapt this code.
The two exceptions to all this are
1. The special chunk `top' doesn't bother using the
trailing size field since there is no next contiguous chunk
that would have to index off it. After initialization, `top'
is forced to always exist.
If it would become less than
MINSIZE bytes long, it is replenished.
2. Chunks allocated via mmap, which have the second-lowest-order
bit M (IS_MMAPPED) set in their size fields.
Because they are
allocated one-by-one, each must contain its own trailing size field.
free的实现
free过程是malloc过程逆过程,瞅瞅框架!常识告诉我们,free必须通过某种方式知道要释放的大小才能完成释放工作,因此开篇的问题,将在这里获得最终答案!
首先,这是实现代码
void __libc_free(void *mem)
mstate ar_
void (*hook) (void *, const void *)
= atomic_forced_read(__free_hook);
if (__builtin_expect(hook != NULL,)) {
(*hook) (mem, RETURN_ADDRESS());
if (mem == 0)
p = ((mchunkptr) ((char *) (mem) - 2 * (sizeof(size_t))));
if (chunk_is_mmapped(p)) {
if (!mp_.no_dyn_threshold
&& p-&size & mp_.mmap_threshold
&& p-&size &= DEFAULT_MMAP_THRESHOLD_MAX) {
mp_.mmap_threshold = ((p)-&size & ~(SIZE_BITS));
mp_.trim_threshold = 2 * mp_.mmap_
LIBC_PROBE(memory_mallopt_free_dyn_thresholds, 2,
mp_.mmap_threshold, mp_.trim_threshold);
munmap_chunk(p);
ar_ptr = (((p)-& size & 0x4) ?
((heap_info *) ((unsigned long) (p) & ~((10 * 10) - 1)))-&ar_ptr : &main_arena);
_int_free(ar_ptr, p, 0);
0、动态分配的hook,参考gnu相关内容(google __free_hook),这里忽略它,虽然它代码的一大坨,但和讨论的问题无关! 飘过
1、传入空指针(free(NULL)),直接返回,这个比较熟悉,手册中经常见;
2、p&=&mem2chunk&(mem);这是依据很关键的代码
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
是不是感觉好熟悉,是的,和上文malloc中的 chunk2mem对应的逆操作,上面是加(+),这里是减(-)
3、如果是映射方式分配的大内存,用解映射方式释放,不管它,飘过
4、最后两句
4.1 倒数第二句是宏,展开还是宏,以此继续迭代展开这个样子
ar_ptr = (((p)-& size & 0x4) ?
((heap_info *) ((unsigned long) (p) & ~((10 * 10) - 1)))-&ar_ptr : &main_arena);
大致意思就是依据结构体中布局,检测size的第2位(从0计)是不是1,然后做相应的处理。没有深究,不影响问题的讨论,暂且不论了!(贴出来给深究的人,避免再一层层宏展开了)
4.2 最后一句,_int_free,它要完成释放的工作,因此_libc_free也是个封装
_int_free这也是一个不小的函数,飘过与问题无关的,抓住与问题相关的,只有一句,这一句将揭开问题的答案!
进此函数有一句
size = chunksize (p);
chunksize是个宏
#define PREV_INUSE 0x1
#define IS_MMAPPED 0x2
#define NON_MAIN_ARENA 0x4
#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
#define chunksize(p)
((p)-&size & ~(SIZE_BITS))
5句话表达的意思就就是屏蔽掉结构体size成员的低3位,就得到chunk的大小了,chunk是什么——姑且翻译成内存块,NND,它就是malloc真实分配的大小。参见上面malloc_chunk details注释的chunk示意图!
#include &stdio.h&
#include &stdlib.h&
#include &malloc.h&
struct malloc_chunk {
size_t prev_
struct malloc_chunk *
struct malloc_chunk *
struct malloc_chunk *fd_
struct malloc_chunk *bk_
typedef struct malloc_chunk *
int main(int argc, char *argv[])
for(i = 0; i & 10; ++i) {
mem = malloc(i);
p = ((mchunkptr) ((char *) (mem) - 2 * (sizeof(size_t))));
printf(&malloc size : %d; chunk size : %d\n&, i, p-&size & ~0x7);
free(mem);
for(i = 0; i & 10; ++i) {
mem = malloc(ret = rand() % 1024);
p = ((mchunkptr) ((char *) (mem) - 2 * (sizeof(size_t))));
printf(&malloc size : %d; chunk size : %d\n&, ret, p-&size & ~0x7);
free(mem);
如果malloc和free是你的开发产品中的性能瓶颈,可以自行实现malloc和free,据说很多公司这样做了!!!
大功告成!
最后,先要再次提醒这是glib C的。至于windows下其怎么malloc和free的,有兴趣自己研究吧!!!
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42373次
排名:千里之外
原创:44篇
(1)(1)(1)(1)(7)(3)(3)(1)(1)(1)(8)(1)(6)(4)(1)(1)(1)(1)(1)(1)

我要回帖

更多关于 蜗居百度云网盘 的文章

 

随机推荐