- 16~64B的内存块会被添加入fastbinY中
- samll及large的会添加在bins中的unsorted bins中 。
tips:small bins和large bins中索引的内存块是在内存分配的过程中被添加在相应的bin中的 。内存分配内存分配的流程如下图所示:
文章插图
我们知道,内存分配的最终目的在于分配出合适大小的内存块返回给用户 。在实现中即为在bin或top chunk中找到(并分割出)所需内存块,其检索的优先级从高到低分别是:
- fastbinY
- small bins
- unsorted bins
- large bins
- top bins
tips: Fast bin、Unsorted bin、Small bin和 Large bin中保存的都是用户曾经释放的内存块(可能经过合并); top chunk包含Arena扩容的部分,不属于任何bin!chunk级分析本文不过度关注操作细节,因此有关内存回收的过程就不赘述了 。下图即内存分配的详细过程图:
文章插图
tips:保存或新窗口打开图片可以查看原图 。具体分配说明参见下列引用内容:
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 bins和unsorted bin中都找不到合适的 chunk,并且fast bins和unsorted bin中所有的chunk都清除干净了 。从large bins中按照“smallest-first,best-fit”原则,找一个合适的 chunk,从中划分一块所需大小的chunk,并将剩下的部分链接回到bins中 。若操作成功,则分配结束,否则转到下一步 。
9、如果搜索fast bins和bins都没有找到合适的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 的大小 。
推荐阅读
- 图解希尔排序,超详细非常好理解
- 深入理解 C 语言的 hello world
- JAVA并发之ReentrantLock原理解析
- 如何理解c/c++和php语言的区别
- 如何理解中台?
- C/C++|图文深入理解函数调用的5种约定
- Linux 升级gcc g++ gdb glibc教程
- TCP和UDP的区别,深入理解TCP三次握手和四次挥手的全过程
- 微软在Edge浏览器中更深入整合Office功能
- linux内核--自旋锁的理解