c malloc分配内存

http://www.cnblogs.com/taek/p/3946605.html

  php中的内存分配有用类似emalloc这样的函数,emalloc实际上是C语言中的malloc的一层封装,php启动后,会向OS申请一块内存,可以理解为内存池,以后的php分配内存都是在这块内存池中进行的,以至于efree,也不会向OS退回内存,而只是设置标志位,标识efree这块内存不再使用了,这样做的好处是,速度快,避免系统调用,因为频繁的从用户态和内核态之间的切换是很费CPU的。

  C语言的malloc函数的后面是glibc(内存管理系统) , 前段时间在看到php内存分配时,看到了emalloc,又延伸看到malloc,只是知道malloc向OS索要一部分内存,但内在的原理不知,索性google ,baidu了malloc背后的知识,脑洞大开,不禁惊叹,自己掌握的知识太少了,虽然现在主要使用php写东西,基本不用C,但知道一些底层的东西,也是有好处的。

  一般linux默认使用的内存管理系统是ptmalloc

  先上一个内存分布的图

  

 

  从低地址到高地址依次是:

     1)代码段

  2)数据段 :定义的全局变量和静态变量

  3)BSS段:未定义的全局变量和静态变量

  4)常量区

    5)heap:堆

  6)mmap:内存映射段

  7)stack:栈

  8)kenal space: 内核空间

  

    ptmalloc管理的就是这个heap,

  在写C程序时,肯定会有一个main函数,在执行时,main不是第一个执行的函数,而是有另一个函数优先于他先执行,这个时候,他会向OS要一大块内存,也可以理解为内存池,这个优先运行的函数也会进行一些分配内存,释放内存之类的操作,我们写C程序中关于分配内存的操作也是基于这个内存池进行的

      ptmalloc把管理的内存分成若干大小的chunk,其结构体如下

  

复制代码
struct malloc_chunk{
    INTERNAL_SIZE_T  pre_size;
    INTERNAL_SIZE_T  size;
    struct malloc_chunk *fd;
    struct malloc_chunk *bk;
    struct malloc_chunk *fd_nextsize;
    struct malloc_chunk *bk_nextsize;
};                   
        
复制代码

 

  pre_size:表示前一个空闲的chunk的大小,如果不空闲,则该字段无意义

  size:当前chunk的大小

  fd,bk:只有当当前的chunk为空闲时,才有用,fd表示forward下一个空闲chunk bk表示上一个空闲chunk ,

      当当前的chunk不为空闲时,即分配出去了,fd,bk 是没用的,,因为该chunk已从相应bins中剔除了

  fd_nextrsize,bk_nextsize:当当前chunk存放于large bins时,largs bins里里面的chunk是从大到小排列的,有可能存在多个相同大小的chunk,这时fd_nextsize,bk_nextsize就派上了用场,fd_nextsize表示大于当前chunk的第一个空闲chunk,

                bk_nextsize表示小于当前chunk大小的第一个空闲chunk, 当当前chunk被分配出去时,这两个字段也就没用了,因为该chunk已从相应bins中剔除了

 

 

    之前看栈与堆的区别时,有的文章说malloc是在一个被链表连接起来的未使用的内存进行寻找的,这么说也没错,只是将未使用的内存连接起来的不是一个链表,而是多个

    ptmalloc把空闲的chunk按大小,放进4个bins(箱子中),这些箱子可以看做是 指针数组+双向循环链表

 

  

    

 

   unsorted bins : 缓冲区

  small bins:一共63个,每一列bins子中的chunk大小都相同,但不同列的bins中的chunk大小不同,相差8字节

    large bins:称为不定长箱子,从512字节开始,从大到小排序

  fast bins : 大概有10个bin,可以理解为高速缓存区,基本上在64字节以下的空闲chunk,都存放这里,但在某种情况下,会合并,并放到unsorted bin中

   

  __init_malloc()

  1)如果要分配的内存大于fastbins中最大的chunk,根据待分配内存的大小,计算出索引值,再通过该索引找到头指针,取出第一个chunk, 返回给调用者

  2)从smallbins中查找,如果找到返回chunk

  3)smallbins中找不到,则从unsorted bins中查找,遍历它

    如果unsorted bins只有一个chunk,并且该chunk大于待分配内存大小,则进行切割,余下的chunk仍放回unsorted bins中

    如果unsorted bins中的某一chunk大小 正好等于 待分配内存大小,则返回,并从unsorted bins中删除

    如果unsorted bins中的某一chunk大小 属于small bins的范围,则放入small bins的头部

    如果unsorted bins中的某一chunk大小 属于big bins的范围,则根据情况判断:

      根据unsorted binsk 中这个chunk 的大小,计算出所在big bins的索引值,根据此值,找到链表头 (放入bitMap中,表示该chunk可使用)

        如unsorted bins中这个chunk 的大小 小于这个链表中最小的chunk,那么直接放到后面

         如unsorted bins中这个chunk 的大小 不小于这个链表中最小的chunk, 那么就要循环这个链表,直到找到一个合适位置

  4)从big bins中查找,找到链表头后,反向遍历此链表,直到找到第一个大小 大于待分配的chunk,然后进行切割,如果有余下的,则放入unsorted bin中去

  5)将上面的索引值加1,进行位图法搜索,位图法简单来说是,利用整形int中的每一个位,可以表示一个数字,这样可节省空间,

  6)如果还没有找到,对top chunk进行分割,

  7)如果存在fastbin, 则进行合并放入unsorted bins中,并回到3中

  8)根据情况,如果所需内存地址 小于128K,使用brk在堆上进行分配,同时将top chunk收缩,如果大于128K,则使用 mmap申请内存

 

  位图法:

  C语言中 int a; 在8 size大小的机器中, a占32位,即

 

 

00000000000000000000000000000000

 

  为了减少空间,将数字按位放到上面的表格中去,例如数字8,二进制为1000

00000000000000000000000000001000

 

 为了计算数字8在表格中的位置,可将8对31求余 ,也可以这样:8&31=8

 

  对于,整形数组 int a[4] , 数字 12, 位于第0行,第12列

  第0行   12/32  12>>5

  第12列  a[0]|=1<<(12&(1<<5-1))

 

00000001000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000

  

  

  对于ptmalloc来说,前两行全是small bins ,后两行全是big bins,所以在进行bit map查找时,因为索引值已加1,所以找到的第一个单元格如果是空闲的,则大小必定满足条件

 

  _int_free

  1)如果free的内存大小 在fastbins范围内,则直接放入相应index对应的链表的第一个chunk上,这里使用 无锁 实现

  2)如果不在 fastbins范围内,且不属于mmap分配的内存,则看前一块内存是否不再使用,如果是,则合并;再看后一块内存如果不是top chunk,也进行合并,并放入unsorted bins中

    如果后一块内在是top chunk,则与top chunk合并,

    如果上述合并的内存大小 超过64K,则将fastbins中的内存进行合并,一同放入unsorted bins中去

    如果 top chunk的大小超过128K,则堆进行收缩,向OS真正的退回内存

  3)如果是mmap申请的内存,则直接向OS退回内存


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值