STL源码剖析——内存空间管理

来源:互联网 发布:新浪微博seo 编辑:程序博客网 时间:2024/05/20 00:52

STL内存空间管理工具alloc

1.第一级配置器__malloc_alloc_template

staic void *allocate(size_t n) {    void *result = malloc(n);//直接调用malloc    if (0 == n) result = oom_malloc(n);    return result;}static void *deallocate(void *p, size_t n) {    free(p);}static void *reallocate(void *p, size_t old_size, size_t new_size) {    void *result = realloc(p, new_size);    if (result == 0) result = oom_realloc(p, new_size);    return result;}

很明显一级配置器只是简单的对C函数malloc, free, realloc的封装,当malloc, realloc向系统申请空间失败时,这两个函数反复调用用户传过来的out of memory handler处理函数,直到申请到内存为止(类似C++的set_new_handler)。如果用户并没有传递__malloc_alloc_oom_handler则抛出__THROW_BAD_ALLOC异常 。

2.第二级配置器__default_alloc_template

第二级配置器为了避免小额区块造成的内存碎片问题,采用内存池来管理内存。当请求的内存大于128bytes时转调用第一级配置器。小于等于128bytes时就从此配置器维护的内存池中分配内存。

内存池采用free_list维护空闲内存空间,free_list如下

这里写图片描述

free_list 是这些空闲链表的起始地址组成的数组,大小为16,每个链表中空闲空间的大小都是固定的,大小分别为8,16,24,32,40,48 , 56 , 64 , 72 , 80 … 128bytes。还有两个指针start_free, end_free分别指向内存池的首尾,heap_size记录已分配出去的总大小。

内存分配规则如下

1.如果申请的内存空间大于128,转调用第一级配置器
2.将申请空间的大小上调至8的倍数size,并根据size找出对应的空闲链表地址free_list[index]
3.如果free_list[index]不为空则将此地址返回,free_list[index]指向空闲链表下个节点,为空则到4
4.此时free_list[index]中没有空闲块可用,调用refill函数,重填free_list

fefill过程如下:
1.调用chunk_alloc尝试申请大小为20 * size的空间,但是不一定能申请到20 * size
2.如果只获得了size * 1大小的空间,就把此空间分配给调用者,free_list无新节点,否则,将分配的空间的第一块返回给调用者,其余空间串接到free_list[index]维护的空闲链表上

chunk_alloc过程:
1.如果内存池空间(end_free - start_free)够 size * n(n默认为20),则将空间分配出去,更新start_free,否则到2
2.内存池空间不够size * n,但是大于size,则分配 (end_free - start_free) / size个size大小的空间,更新start_free,否则到3
3.此时说明内存池剩余空间一个size大小的区块都不能提供,如果内存池中还有剩余空间(肯定小于size)则将此空间连接到到对应的空闲链表中
4.调用malloc申请 2 * size * n + ROUND_UP(heap_size >> 4)大小的空间,如果申请成功,更新start_free, end_free, heap_size,并重新调用chunk_alloc(更新n,即实际分配的区块数),否则到5
5.此时malloc也申请失败,则遍历free_list[index]到free_list[15],只要有一个空闲,就释放出该链中的一个区块,更新start_free,end_free分别指向此块的首尾,再重新调用chunk_alloc(更新n,即实际分配的区块数)

内存释放规则如下

函数原型static void deallocate(void *p, size_t n);
如果n > 128则调用第一级配置器直接free,否则调整free_list,回收此区块,将此区块添加到对应的free_list[index]维护的空闲链表中