`
mqzhuang
  • 浏览: 185499 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Glibc内存管理--ptmalloc2源代码分析(七)

阅读更多

3.2.4 内存分配概述

  1. 分配算法概述,以32系统为例,64位系统类似。

  • 小于等于64字节:用pool算法分配。
  • 64512字节之间:在最佳匹配算法分配和pool算法分配中取一种合适的。
  • 大于等于512字节:用最佳匹配算法分配。
  • 大于等于mmap分配阈值(默认值128KB:根据设置的mmap的分配策略进行分配,如果没有开启mmap分配阈值的动态调整机制,大于等于128KB直接调用mmap分配。否则,大于等于mmap分配阈值时才直接调用mmap()分配。 

2.       ptmalloc的响应用户内存分配要求的具体步骤为:

  1.   获取分配区的锁,为了防止多个线程同时访问同一个分配区,在进行分配之前需要取得分配区域的锁。线程先查看线程私有实例中是否已经存在一个分配区,如果存在尝试对该分配区加锁,如果加锁成功,使用该分配区分配内存,否则,该线程搜索分配区循环链表试图获得一个空闲(没有加锁)的分配区。如果所有的分配区都已经加锁,那么ptmalloc会开辟一个新的分配区,把该分配区加入到全局分配区循环链表和线程的私有实例中并加锁,然后使用该分配区进行分配操作。开辟出来的新分配区一定为非主分配区,因为主分配区是从父进程那里继承来的。开辟非主分配区时会调用mmap()创建一个sub-heap,并设置好top chunk
  2. 将用户的请求大小转换为实际需要分配的chunk空间大小。
  3. 判断所需分配chunk的大小是否满足chunk_size <= max_fast (max_fast 默认为 64B),如果是的话,则转下一步,否则跳到第5步。
  4. 首先尝试在fast bins中取一个所需大小的chunk分配给用户。如果可以找到,则分配结束。否则转到下一步。
  5. 判断所需大小是否处在small bins中,即判断chunk_size < 512B是否成立。如果chunk大小处在small bins中,则转下一步,否则转到第6步。
  6.  根据所需分配的chunk的大小,找到具体所在的某个small bin,从该bin的尾部摘取一个恰好满足大小的chunk。若成功,则分配结束,否则,转到下一步。
  7. 到了这一步,说明需要分配的是一块大的内存,或者small bins中找不到合适的 chunk。于是,ptmalloc首先会遍历fast bins中的chunk,将相邻的chunk进行合并,并链接到unsorted bin中,然后遍历unsorted bin中的chunk,如果unsorted bin只有一个chunk,并且这个chunk在上次分配时被使用过,并且所需分配的chunk大小属于small bins,并且chunk的大小大于等于需要分配的大小,这种情况下就直接将该chunk进行切割,分配结束,否则将根据chunk的空间大小将其放入small bins或是large bins中,遍历完成后,转入下一步。
  8. 到了这一步,说明需要分配的是一块大的内存,或者small binsunsorted bin中都找不到合适的 chunk,并且fast binsunsorted bin中所有的chunk都清除干净了。从large bins中按照“smallest-firstbest-fit”原则,找一个合适的 chunk,从中划分一块所需大小的chunk,并将剩下的部分链接回到bins中。若操作成功,则分配结束,否则转到下一步。
  9. 如果搜索fast binsbins都没有找到合适的chunk,那么就需要操作top chunk来进行分配了。判断top chunk大小是否满足所需chunk的大小,如果是,则从top chunk中分出一块来。否则转到下一步。
  10. 到了这一步,说明top chunk也不能满足分配要求,所以,于是就有了两个选择: 如果是主分配区,调用sbrk(),增加top chunk大小;如果是非主分配区,调用mmap来分配一个新的sub-heap,增加top chunk大小;或者使用mmap()来直接分配。在这里,需要依靠chunk的大小来决定到底使用哪种方法。判断所需分配的chunk大小是否大于等于 mmap分配阈值,如果是的话,则转下一步,调用mmap分配,否则跳到第12步,增加top chunk 的大小。
  11. 使用mmap系统调用为程序的内存空间映射一块chunk_size align 4kB大小的空间。 然后将内存指针返回给用户。
  12. 判断是否为第一次调用malloc,若是主分配区,则需要进行一次初始化工作,分配一块大小为(chunk_size + 128KB) align 4KB大小的空间作为初始的heap。若已经初始化过了,主分配区则调用sbrk()增加heap空间,分主分配区则在top chunk中切割出一个chunk,使之满足分配需求,并将内存指针返回给用户。  

    总结一下:根据用户请求分配的内存的大小,ptmalloc有可能会在两个地方为用户分配内存空间。在第一次分配内存时,一般情况下只存在一个主分配区,但也有可能从父进程那里继承来了多个非主分配区,在这里主要讨论主分配区的情况,brk值等于start_brk,所以实际上heap大小为0top chunk大小也是0。这时,如果不增加heap大小,就不能满足任何分配要求。所以,若用户的请求的内存大小小于mmap分配阈值,则ptmalloc会初始heap。然后在heap中分配空间给用户,以后的分配就基于这个heap进行。若第一次用户的请求就大于mmap分配阈值,则ptmalloc直接使用mmap()分配一块内存给用户,而heap也就没有被初始化,直到用户第一次请求小于mmap分配阈值的内存分配。第一次以后的分配就比较复杂了,简单说来,ptmalloc首先会查找fast bins,如果不能找到匹配的chunk,则查找small bins。若还是不行,合并fast bins,把chunk加入unsorted bin,在unsorted bin中查找,若还是不行,把unsorted bin中的chunk全加入large bins中,并查找large bins。在fast binssmall bins中的查找都需要精确匹配,而在large bins中查找时,则遵循“smallest-firstbest-fit”的原则,不需要精确匹配。若以上方法都失败了,则ptmalloc会考虑使用top chunk。若top chunk也不能满足分配要求。而且所需chunk大小大于mmap分配阈值,则使用mmap进行分配。否则增加heap,增大top chunk。以满足分配要求。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics