1. free源码分析—_int_free
根据上一章的分析可知,如果一个chunk不是由mmap分配得到,就会调用_int_free
进行释放。下面来看,
|
|
1.1 _int_free第一部分
首先来看_int_free
第一部分,为了便于分析,这里省略了一些不关键的代码,
|
|
第一部分首先是检查size
变量的合法性,然后比较get_max_fast()
判断size
是否在fastbin的范围内,如果在fastbin的管理范围内,就通过set_fastchunks
设置分配区的标志位表示fastbin有空闲chunk,接下来根据size
获得即将添加的chunk在fastbin中的索引idx
,并通过该索引获得头指针fb
,最后通过CAS操作将该chunk添加到fastbin中。这里需要注意fastbin中存放的chunk是按照单向链表组织的。
1.2 _int_free第二部分
继续往下看,为了使整个代码结构清晰,这里保留了上一部分的if,
|
|
如果将要释放的chunk不属于fastbin,且不是由mmap分配的,就首先获得下一个chunk的指针nextchunk
和大小nextsize
,如果前一个chunk空闲,就和前一个chunk合并,并通过unlink
将该chunk从空闲链表中脱离。接下来,如果刚才前面取出的下一个chunk也为空闲,并且该chunk不是top chunk,则继续合并,否则将其设为空闲。再往下,就是取出unsortedbin的头指针,将合并后的chunk插入unsortedbin链表头部,并进行相应的设置。
如果下一个chunk为top chunk,就将要释放的chunk合并到top chunk中。
1.3 _int_free第三部分
继续往下看,
|
|
如果前面释放的chunk比较大,就需要做一些处理了。首先对fastbin中的chunk进行合并并添加到unsortedbin中。然后,如果是主分配区,并且主分配区的top chunk大于一定的值,就通过systrim
缩小top chunk。如果是非主分配区,就获得top chunk对应的非主分配区的heap_info
指针,调用heap_trim
尝试缩小该heap。后面来看systrim
和heap_trim
这两个函数。
最后,说明chunk还是通过mmap分配的,就调用munmap_chunk
释放它。munmap_chunk
函数已经在上一章介绍了。
1.4 systrim
systrim
用于缩小主分配区的top chunk大小,下面来看,
|
|
首先,如果主分配区的top chunk本来就没什么空间,就直接返回,否则就将主分配区中可以缩小的大小保存在extra
中。下面检查当前堆的brk
指针是否和top chunk的结束地址相等,如果相等就可以通过MORECORE
降低堆的大小,MORECORE
是brk的系统调用,最后也是通过do_munmap
释放虚拟内存的。__after_morecore_hook
函数指针为空,不管它。再下来,获得释放后的堆指针保存在new_brk
中,计算释放的虚拟内存的大小released
,并将该信息更新到主分配区中,然后设置新top chunk的size
。
1.5 heap_trim
heap_trim
用来缩小非主分配区的heap大小,下面来看,
|
|
第一个while表示,如果top chunk指针正好在heap_info
上,则考虑删掉整个heap。这是因为此时,该heap只有一个top chunk。再删掉该heap之前,需要检查该heap的前一个heap是否有足够的空间,否则删掉该heap后,剩余的空间太小。
经过计算后,newsize
保存了前一个heap高地址处的fencepost和前一个空闲chunk(如果存在)的总大小组成,如果newsize
加上该heap还未使用的内存(HEAP_MAX_SIZE - prev_heap->size
)太小,就break
退出循环,取消对整个heap的释放。否则,在更新了相应的信息后,调用delete_heap
删除整个heap,delete_heap
是一个宏,定义如下
|
|
delete_heap
其最终通过__munmap
释放整个heap,大小为HEAP_MAX_SIZE
。
删除掉整个heap后,如果前一个heap的fencepost的前面有一个空闲chunk,就将该空闲chunk从空闲链表中脱离,然后设置fencepost或者该空闲chunk(如果存在)的地址为新的top chunk,该top chunk的大小为前面计算的new_size
。
然后返回while
继续检查,如果新的top chunk指针又正好在heap_info
上,就表示该heap也就只有一个chunk即top chunk,就继续释放该heap。
再往下,如果新的top chunk剩余空间top_area
太小,就直接返回了。如果还有足够的空间,且top_area
大于收缩阀值,就调用shrink_heap
进一步将新的top chunk的大小减少extra
。最后设置一些分配区的信息,并设置减少后的top chunk的大小为top_size - extra
。
|
|
这里其实就是减小heap_info
的size
变量。
2. 总结
下面对整个_int_free
函数做个总结。
首先检查将要释放的chunk是否属于fastbin,如果属于就将其添加到fastbin中。
然后检查该chunk是否是由mmap分配的,如果不是,就根据其下一个chunk的类型添加到unsortedbin或者合并到top chunk中。
接着,如果释放的chunk的大小大于一定的阀值,就需要通过systrim
缩小主分配区的大小,或者通过heap_trim
缩小非主分配区的大小。
最后如果该chunk是由mmap的分配的,通过munmap_chunk
释放。