SGISTL源码探究-内存池

前言

在本小节中我们将讲解chunk_alloc函数,从内存池中取空间给free_list,这便是chunk_alloc需要做的事。

chunk_alloc

引入

该函数的大致逻辑是:
若内存池的容量够需求,则直接返回给free_list;如果不够,能分多少就分多少给free_list;如果一个都分不了,则看看内存池还有没有剩余的零头,如果有的话,分给其他free_list,然后对内存池进行补充容量(malloc申请),如果申请失败,只好依靠没有用的且足够大的free_list了,最后实在哪里都没有内存可以拿出来了,只能调用第一级配置器,看看oom机制能否坚持到有内存可用。

深入源码
/* We allocate memory in large chunks in order to avoid fragmenting     */
/* the malloc heap too much.                                            */
/* We assume that size is properly aligned.                             */
/* We hold the allocation lock.                                         */
template <bool threads, int inst>
char*
__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;
    /* 若容量够total_bytes,直接分配
     * 否则能分配几个节点分配几个
     * 一个都不能满足,那把内存池剩余的空间分给其他的free_list,并重新填充内存池
     */
    if (bytes_left >= total_bytes) {
        result = start_free;
        start_free += total_bytes;
        return(result);
    } else if (bytes_left >= size) {
        //nobjs传入的是引用,所以此时会变成实际上能满足的节点个数
        nobjs = bytes_left/size;
        total_bytes = size * nobjs;
        result = start_free;
        start_free += total_bytes;
        return(result);
    } else {
        /* bytes_to_get代表要申请的容量
         * 注意是总容量的2倍加附加量,分total_bytes给free_list,剩下的留给内存池
         */
        size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
        // Try to make use of the left-over piece.
        //尝试将剩余的空间分给满足的free_list
        if (bytes_left > 0) {
            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了
             * 足够大小是指,至少能满足一个free_list块的大小(因为调用的递归,而递归的出口就满足total_bytes或者满足一个节点)
             */
            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机制了
         * 因为之前malloc都没成功,所以第一级去malloc多半也会失败,好在第一级配置器有个oom机制
         * 最后实在不行,会抛出bad_alloc异常
         */
        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.
        }
        /* 走到这一步证明已经突破了重重困难将容量申请成功了
         * 调整heap_size及end_free
         * 最后再次调用chunk_alloc,将容量分配给free_list
         */
        heap_size += bytes_to_get;
        end_free = start_free + bytes_to_get;
        return(chunk_alloc(size, nobjs));
    }
}
小结

以上便是chunk_alloc的做法,需要特别注意的一点是填充内存池的时候,申请的容量是free_list需要的容量的2倍加上附加量,这点和vector容器很像。之后将需要的容量返回,剩下的留给内存池,供下次调用chunk_alloc时使用。
接下来我们将整理一下空间配置器整体的知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值