glibc malloc和free
主arena
heap和arena
根据他们在堆中出现的次序,第一个是heap_info,即Heap这个结构的元数据,即它本身拥有的用来指示在它上面的操作的数据。
1 | typedef struct _heap_info { |
从这个结构当中,
我们可以推断出heap和arena是有一个对应关系的,
以及prev指针说明了heap本身是由一个链表连接的,
事实上是一个循环单链表。
state结构
或者叫mstate,
虽然名称似乎和arena没有关系,
但是其实这个结构是用来表示arena的。
1 | struct malloc_state { |
Mutex
用来保证同步,在调用一个函数,比如malloc的时候,
其实调用的是public_xxx的函数,
而这个函数的认为就是先试图进行加锁,
这个锁就是这里的mutex了,然后再调用_int_xxx函数,
这个函数才是真正的内部实现。
flags
用来表示一些当前arena的特征,比如是否有fastbin chunk存在,内存是否是非连续的等等。
fasbins[…]
这个数组存的是fastbin的链表,
每一个数组中的元素对应一个fastbin的链表,
bin为chunk的链表,保存没有被使用的chunk,
用来避免多次使用系统调用分配。总共有4种bin,
包括fastbin,small bin, large bin和unsorted bin,
主要用于分配,在分配的时候,会根据大小去查找到相应的bin,
然后通过在bin中删除某一个块来进行分配。
Fastbin是4种bin中唯一使用单链表表示的bin
top
top chunk,较为特殊的一个chunk,
虽然其数据结构(后文会谈到的chunk的结构)和一般chunk无异,
但是他相当于堆可用内存的一个边界,
是唯一一个可以自行增长的chunk,
每当在各个bin当中去找空余的内存找不到的时候就会来这儿取一个块,
剩下的就是remainder块,也是新的top块
last_remainder
上面的top chunk已经谈到了,
其实就是从top chunk当中分出去之后剩下的那一个块
bins[…]
在fastbin的解释当中我们提到了有4种bin,
由于只有fastbin是单链表表示,所以fastbin是单独表示的,
其他bin则都使用了这个bins数组,下标1是unsorted bin,
2到63是small bin,64到126是large bin,共126个bin。
bitmap[…]
表示bin数组当中某一个下标的bin是否为空,
用来在分配的时候加速 .next
下一个arena,是一个循环单链表
system_mem和max_system_mem
用来跟踪当前被系统分配的内存总量,
INTERNAL_SIZE_T数据类型在大多数系统上都是size_t
chunk
32位中chunk结构为
4字节前一个堆块大小
4字节本堆块size(最后三位flag)
快表中
[
4字节(不使用堆块的情况下前一个堆块指针)
]
非快表
[
4字节(不使用堆块的情况下前一个堆块指针)
4字节(不使用堆块的情况下后一个堆块指针)
]
64位翻倍
malloc
第一步:如果进程没有关联的分配区,
就通过sysmalloc从操作系统分配内存mmap
第二步:从fastbin查找对应大小的chunk并返回(效验下一块是否存在),
如果失败进入第三步。
第三步:从smallbin查找对应大小的chunk并返回,
如果分配失败将fastbin中的空闲chunk合并放入unsortedbin中,
进入第四步。
(如果前一个空闲则unlink前一个然后合并,
然后检查下一个是否空闲。
如果相邻的下一个chunk不是top chunk,
并且下一个chunk不在使用中,
就继续合并,否则,就清除下一个chunk的PREV_INUSE,
表示该chunk已经空闲了。 然后将刚刚合并完的chunk添加进unsorted_bin中,
unsorted_bin也是一个双向链表。 )
第四步:遍历unsortedbin,
从unsortedbin中查找对应大小的chunk
并返回如果满足拆开的大小则拆成两部分,
后面部分放回unsortedbin,
根据大小将unsortedbin中的空闲chunk插入smallbin或者largebin中。
进入第五步。
第五步:从largebin指定位置查找对应大小的chunk并返回,
如果失败进入第六步。
第六步:从largebin中大于指定位置的双向链表中
查找对应大小的chunk并返回,如果失败进入第七步。
第七步:从topchunk中分配对应大小的chunk并返回,
topchunk中没有足够的空间,就查找fastbin中是否有空闲chunk
如果有,就合并fastbin中的chunk并加入到unsortedbin中,
然后跳回第四步。如果fastbin中没有空闲chunk,
就通过sysmalloc从操作系统分配内存。
sysmalloc先试图扩大top chunk,如果失败就申请一个新的topchunk
并释放原来的topchunk。如果申请新的则扩大阈值
free
下面对整个_int_free函数做个总结。
首先检查将要释放的chunk是否属于fastbin,
如果属于就将其添加到fastbin中
(检查下一块的大小是 否为合理的数值)。
然后检查该chunk是否是由mmap分配的,
如果不是找前一个unlink合并,
就根据其下一个chunk的类型添加到unsortedbin
或者合并到top chunk中。
接着,如果释放的chunk的大小大于一定的阀值,
就需要通过systrim缩小主分配区的大小,
或者通过heap_trim缩小非主分配区的大小。
(检查unsortbin是否完好无损)
最后如果该chunk是由mmap的分配的,
通过munmap_chunk释放。