Ptmalloc总结

有关于ptmalloc的一些总结

在glibc下的ptmalloc的一点点分析。数组

关于chunk组织

图片描述

  • chunk指针指向一个chunk的开始处,而mem指针才是真正分配给用户的储存空间。
  • chunk的第二个域的最低一位P表示前一个chunk是不是在使用当中(0表明前一个空闲,1表明在使用当中)。
    当P为0时,此时prev_size才有效,第一个域表示的是前一个chunk的size,能够经过这个值取到前一个chunk的开始地址;当P为1时,表示前一个chunk在使用当中,prev_size无效。
    ptmalloc分配的第一个chunk老是将P设为1,以防止程序引用到不存在的区域。
  • chunk第二个域倒数第二位M(0表示是从mmap映射区域分配的,1表示heap区域分配)
  • chunk第二个域倒数第三位A(1表示主分配区,0非主分配区)
  • 当chunk空闲时,user_data区域储存了4个指针。
    指针fd指向后一个空闲的chunk;
    指针bk指向前一个空闲的chunk;
    fd_nextsize以及bk_nextsize两个指针用于加快在large bin中查找最近匹配的空闲chunk
  • chunk利用标志来管理使用和空闲的内存,减小了内存归还所带来的系统消耗,而且在一个未使用的chunk中,它的prev_size部分是能够被紧挨的上一个使用的chunk空间复用的。

关于bins

用户free掉的内存并非直接就归还给系统,ptmalloc会统一管理heap和mmap映射区域中的空闲chunk,当用户有分配请求时候,ptmalloc会首先在空闲的chunk中挑选一块符合需求的交给用户,这样避免了频繁的系统调用,下降了内存分配的开销。函数

  • ptmalloc将类似大小的chunk用双向链表连接起来,这样的一个链表就被叫作bin,ptmalloc一共维护了128个bin,并用一个数组来储存这些bin图片描述
  • 数组第一个是unsorted bin,ptmalloc在合并空闲的chunk时会放入,若是用户释放的chunk大于max_fast或者fast bins中空闲的chunk合并以后都会放入unsorted bin中。
    ptmalloc在fast bins中没有找到合适的chunk就会进入unsorted bins中查找,若是仍是没有找到,就会把unsorted bin汇总的chunk加入到bins当中,这样看来,unsorted bin相似于bins中的一个缓冲区。
  • 数组的2到64个bin被称为small bins,同一个small bin中的chunk大小相同,两个相邻的small bin相差8字节;
  • 后面64个bin称为large bins,这里面的每个bin都是一个范围内的chunk而且是按大小序排列好的;
  • fast bins
  • 引入它是由于在分配时可能会常常申请和释放一些很小的空间,分配器合并以后又须要分割,这样太太低效,故而在不大于max_fast(默认值是64B)的chunk释放后会先被放到fast_bins中,不去改变他们的P标志位,因此他们没法合并,在小于等于max_fast时首先在fast_bins中查找相应的空闲块。
  • Top chunk
    这是一开始所划分出来的一个大空闲内存,若是bins以后尚未知足的chunk,那么经过Top chunk来划分一个新的chunk给用户
  • mmaped chunk
    当top chunk都不能知足时,经过mmap将页映射到进程空间中,这样的chunk被free时候直接解除映射归还给系统。
  • last remainder
    当所请求的chunk是一个小空间的,可是在small bins中又没有合适的chunk,那么从last remainder chunk中分裂出两个chunk,一个给用户,一个变成新的last remainder chunk。

sbrk和mmap

.bss段之上的分配给用户程序的空间叫作堆,start_brk指向堆的开始,brk指向堆的顶部,能够经过brk()和sbrk()来增长标识堆顶的brk的值。spa

在使用malloc以前brk等于start_brk,请求分配时如果请求空间小于mmap的分配阈值(mmap threshold,默认是128k),主分配区会调用sbrk()增长一块大小为4k的空间做为heap。非主分配区则会调用mmap映射一块HEAP_MAX_SIZE(32位系统下默认1M,64位系统下默认是64M)大小的空间做为sub-heap。操作系统

ptmalloc分配概述

  1. 获取分配区的锁,为了防止多个线程同时访问同一个分配区。
  2. 将用户请求的大小转换位实际须要分配的chunk空间的大小。
  3. 判断所需分配的chunk大小是否小于max_fast,若是大于则跳转第五步。
  4. 首先城市在fast bins中查找一个chunk给用户,若是存在则分配结束。
  5. 判断所需大小是否处在small bins中,若是chunk大小处在small bins中,则根据所需chunk大小,找到具体所在的某个索small bin,从bin的尾部摘取一个知足大小的chunk返回给用户。不然到第六步。
  6. 到了这一步说明分配的是一个大块内存或者small bins中没有合适的chunk。那么首先会遍历fast bins中的chunk与相邻chunk合并连接到unsorted bin中,而后遍历unsorted bin中的chunk,若是只有一个上次分配已经使用的chunk,而且这个chunk知足small bins的要求且这个chunk符合用户所要求的大小,那么直接对这个chunk进行分割返回给用户,不然将它放入small bins或者large bins中。
  7. 排除了fast bins和unsorted bin中的chunk,到了这一步从large bins中找到一个合适的chunk,从中划分一块所需大小的chunk,并将剩余部分连接回bins中,若分配成功则结束,不然下一步。
  8. 若是bins中都没有合适的chunk,那么则对top chunk进行分割来分配给用户,成功则结束,不然下一步。
  9. 到了这一步证实top chunk不能知足需求,那么对于主分配区就调用sbrk()来增长top chunk的大小;对于非主分配区则会调用mmap来分配一个新的sub-heap增长top chunk的大小或者直接mmap()直接映射分配。

关于内存的回收

  1. free()函数也会先获取分配区的锁。
  2. 判空,若是是空直接return。
  3. 判断所需释放的chunk是否是mmaped chunk,如果是,直接调用munmap()释放mmaped chunk,解除内存映射。不然下一步。
  4. 判断chunk的大小和所处的位置,若是chunk_size<=max_fast,而且chunk不在堆顶,也就不与top chunk相邻,则转到下一步,不然转到第六步。
  5. 将chunk放到fast bins中,将chunk放入到fast bins中,并不修改当前的chunk的使用标志P,以后释放结束从free()中返回。
  6. 判断前一个chunk是否在使用当中,若是前一个块也是空闲块那么进行合并。
  7. 判断当前释放的下一个块是否是top chunk,若是是则转到第九步,不然下一步。
  8. 判断下一个chunk是否处在使用中,若是下一个chunk也是空闲的则合并后放入unsorted bin中。
  9. 若是执行到这一步,说明释放了一个和top chunk相邻的chunk。
  10. 判断合并后的chunk大小是否大于FASTBIN_CONSOLDATION_THRESHOLD(默认64KB),若是是则触发进行fast bins的合并操做。
  11. 判断top chunk是否大于mmap的收缩阈值(默认128K),若是是的话,对于主分配区,则会试图归还top chunk中的一部分给操做系统。
相关文章
相关标签/搜索