SGISTL源码阅读三 空间配置器下(内存池memory pool)

SGISTL源码阅读三 空间配置器下(内存池memory pool)

前言

在上一个博客我们讲述了空间配置器的第二级配置器,它的关键点free-lists是依赖于内存池的。在refill中我们通过调用chunk_alloc函数来申请区块,chunk_alloc的作用就是从内存池中取空间给free-lists使用。下面我们通过源码来解读它。

深入源码
template <bool threads, int inst>
char*
//注意,此处nobjs传的是引用
__default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
{
    char * result;
    size_t total_bytes = size * nobjs;
    size_t bytes_left = end_free - start_free;
	//如果剩余空间大于所申请的空间(nobjs个size大小)
    if (bytes_left >= total_bytes) {
    	//调整内存池的起始地址后返回result
        result = start_free;
        start_free += total_bytes;
        return(result);
    //如果剩余空间大于一个size
    } else if (bytes_left >= size) {
    	//调整nobjs
        nobjs = bytes_left/size;
        total_bytes = size * nobjs;
        result = start_free;
        //调整内存池的起始地址,将内存池中所有的空间都返回给free-lists使用
        start_free += total_bytes;
        return(result);
    //内存池中的空间不够了(重点)
    } else {
    	//这里我们可以看到内存池向内存所申请的空间是total_bytes的两倍+附加量
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        // 如果内存池不为空,将其置为空(把所有容量都供free-lists使用)
        if (bytes_left > 0) {
        	//找到对应的free-list并添加进去
            obj * __VOLATILE * my_free_list =
                        free_list + FREELIST_INDEX(bytes_left);

            ((obj *)start_free) -> free_list_link = *my_free_list;
            *my_free_list = (obj *)start_free;
        }
        //向内存中申请空间
        start_free = (char *)malloc(bytes_to_get);
        //如果失败了
        if (0 == start_free) {
            int i;
            obj * __VOLATILE * my_free_list, *p;
            // Try to make do with what we have.  That can't
            // hurt.  We do not try smaller requests, since that tends
            // to result in disaster on multi-process machines.
            //从区块大小更大的free-list中去获取容量
            for (i = size; i <= __MAX_BYTES; i += __ALIGN) {
                my_free_list = free_list + FREELIST_INDEX(i);
                p = *my_free_list;
                if (0 != p) {
                    *my_free_list = p -> free_list_link;
                    //调整内存池的起始地址,并进行递归操作
                    start_free = (char *)p;
                    end_free = start_free + i;
                    return(chunk_alloc(size, nobjs));
                    // Any leftover piece will eventually make it to the
                    // right free list.
                }
            }
            //如果失败了,就只能调用第一级配置器,从oom中寻求解决方案
            //(如果oom机制也没有解决,那么会抛出一个异常,详见第一级配置器https://blog.csdn.net/lyn_00/article/details/83929578)
            end_free = 0;       // In case of exception.
            start_free = (char *)malloc_alloc::allocate(bytes_to_get);
            // This should either throw an
            // exception or remedy the situation.  Thus we assume it
            // succeeded.
        }
        //走到这里,说明已经成功申请了total_bytes的两倍+附加量的空间
        heap_size += bytes_to_get;
        end_free = start_free + bytes_to_get;
        //最后递归调用自己,修正nobjs的值
        return(chunk_alloc(size, nobjs));
    }
}

简要描述一下chunk_alloc的机制
1.如果内存池中的容量足够那么直接将total_bytes(size*nobjs)的空间供free-lists使用。
2.如果内存池中的容量没那么多,但是超过一个size大小,就改变nobjs的值,将内存池中所有的空间给free-lists使用。
3.如果内存池中的容量连一个size大小都没有(这种情况是最复杂的)
(1)将内存池中的容量置零
(2)申请total_bytes的两倍+附加量这么大的空间,如果申请成功了,递归调用它本身,将申请到的容量一半给free-lists,一半存留在内存池中,如果申请失败,见(3)
(3)在free-lists中寻找更大的free-list收回至内存池,再递归调用它本身。如果失败,见(4)
(4)这种情况就是最坏的情况了,我们把它交给第一级配置器的oom机制去处理,最坏的结果是抛出异常。

总结

之前在学习第二级配置器的时候有一个疑惑,现在就清楚了,内存池中处理了申请不到内存的情况。
现在我们对SGISTL的配置器应该也有了一个比较深入的理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值