STL容器alloc学习总结


alloc分配用户内存空间时,会根据用户请求的空间大小进行分配,分为一级配置和二级配置。具体如下:
一.一级配置:创建内存:直接malloc对应大小的内存(针对申请内存大于128)内存销毁:free
二.二级配置:
主要针对内存大小小于128的内存申请,其中主要技术点是free_list和内存池的维护。就我个人的理解,内存池是一个已经向系统heap申请下的空间(malloc),内存池的内存会用来维护free_list数组 ,内存池里面的内存会一直保留着直到程序退出才还给系统。
以下变量是用来标明内存池大小和起始点,内存池是在维持free_list后剩余内存值。
static char *start_free; //内存池起始位置,只在chunk_alloc()中变化
  static char *end_free;//内存池结束为止,只在chunk_alloc()中变化
  static size_t heap_size;//内存池大小

free list是一个数组, 大小为16,用来维护具有不同大小区块的自由链表,存储自由链表表头地址,维护的自由链表中区块大小皆为8的倍数,8,16,24,32,40,48,..........120,128,它们的表头被存储在free_list[]数组中
static obj * __VOLATILE free_list[__NFREELISTS];
free_list 中存储的是表头地址(obj链表第一个obj对象的内存地址0xxxxxxx)而该地址也恰巧是该区块的首地址,在该区块没有使用前,obj的free_list_link为下一区块的首地址.该数组的创建是用于更方便的管理这些自由链表,方便匹配,取值。

free list用来维护具有不同大小区块的自由链表,存储自由链表表头地址,即节点信息存储在区块的前四个字节,在未被用户使用时,区块中存储下一节点地址(free_list_link ),被用户使用后,存储用户数据。当用户申请内存时,数组会根据客户需要的内存大小,匹配合适的区块,然后从该区块的自由链表中取出表头(即数组中存储的地址),并将表头指向的下一区块作为新的表头,取出的表头地址便会成为用户申请地址返回给用户。自由链表节点结构如下:
union obj {//free_list节点结构
  union obj * free_list_link;        //用于标记下一个节点地址
  char client_data[1]; //该字段为free_list_link最后一个字节,考虑到最大的内存区块为128,刚好为一个字节,且在chunk_alloc()中用于下一个内存首地址计算    
  };


以上是alloc中涉及到的一些基本概念,现在来说一下alloc内存创建与销毁的实现
内存的创建:
1.当客户申请一块内存size时(假设小于128,为二级配置)。alloc会根据内存大小在free_list中匹配合适的区块节点(size/8),匹配到后,会在数组中取出该区块自由链表表头地址,返回给用户,并将free_list数组中的该位置替换为表头所指向的下一节点。
2.若free_list中匹配到的自由链表为空,那么会在内存池中获取20*size个字节的内存(连续),并将这段内存转化为obj类型,将第一个节点所在地址返回给客户端,剩余的19个区块组成自由链表存放到free_list对应的位置(size/8)中。
3.若内存池中内存不够20*size,那么会将剩余的内存分配成尽可能多的区块((end_free-start_free)/size>=1)给用户以及free_list。
4.试着让内存池中的残余零头有利用价值,将内存池中剩余的内存分配给合适的区块。((end_free-start_free)+ 8-1)/8-1
5.当内存池中连一个区块也没有时,会通过malloc在系统heap中获取内存放入内存池,获取的内存大小为 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);total_bytes=20*size,获取到的内存会放到内存池中保存,然后通过递归调用,alloc会参照2返回客户一个区块地址,将19个区块写入free_list,而对于剩下的连续内存会放入内存池以供下次区块用完时的处理。
6.而当向系统heap申请内存也失败时,alloc会从free_list中含有更大区块的自由链表中取出一个区块放入内存池保存,然后通过递归调用, 最终返回给客户
7.而当到处都没有内存时,alloc会调用以及配置,看out-of-memory机制能否尽点力(会有异常处理)

内存的销毁:会将需要销毁的内存地址在free_list中匹配对应的位置,将需要销毁的区块节点的下一节点指向自由链表表头,将该区块设置为该自由链表表头。所谓的内存销毁,其实也就是将用户返回的内存存放到内存池,供下次的使用

最近在学习侯捷《STL源码剖析》,以上是自己关于alloc的一些总结,可能存在不足,希望大家能指出

猜你喜欢

转载自blog.csdn.net/qq_39268442/article/details/78890315
今日推荐