STL空间配置器的实现

STL空间配置器的实现

时隔一个半月陆陆续续的将stl空间配置器给啃完了,记下心得
STL源码中二级空间配置器,第一级对new和delete的简单包装没什么好记的,主要是第二级配置器。而第二级配置器主要是几个函数相互调用来实现的。
1.alloc函数即源码中的allocte函数
这个函数主要是用来维护16个自由链表的
2.refill函数
用于alloc与chunk_alloc两个函数之间的交互的(refill函数向内存池中申请内存交给自由链表),alloc函数通过16个链表直接与客端交互。
3.chunk_alloc
chunk_alloc属于底层向系统申请内存,并维护内存池。
以下是源码

#ifndef ALLOCATE
#ifndef bad_alloc
#include<stdlib.h>
#include<stdio.h>
#define bad_alloc "内存不足\n"
#endif // bad_alloc
#define ALLOCATE
class allcate{
private:
    static size_t UP_TO_EIGHT(size_t bytes){
        return ((bytes+7)&~7);
    }
    //自由链表的节点
    union obj{
        obj *free_list_link;
        char client_data[1];
    };
    static obj * volatile free_list[16];//16个自由链表管理
    //根据大小分配自由链表
    static size_t FREELIST_INDEX(size_t bytes){
    return ((bytes+7)/7);
    }
    static void* refill(size_t n);//连接内存池与16个链表
    //内存池的主要构建函数
    static char* chunk_alloc(size_t size_n,int nobjs);
    static char* start_free;//内存池的开头
    static char* end_free;//内存池的结尾
    static size_t heap_size;
public:
    //配置器在16个链表上取出空间
    static void *alloc(size_t n);
    static void dealloc(void *p,size_t n);
    size_t left();
};
char *allcate::
    end_free=0;
char *allcate::
    start_free=0;
size_t allcate::
    heap_size=0;
allcate::obj *volatile allcate::
    free_list[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char* allcate::chunk_alloc(size_t size_n,int nobjs){
    std::cerr<<"进入chunk_alloc函数申请"<<size_n*nobjs<<"大小内存\n";
    char* result;
    size_t total_bytes=size_n*nobjs;
    size_t left_bytes=end_free-start_free;//剩余
    if(left_bytes>=total_bytes){
        std::cerr<<"内存池剩余空间足够多\n";
        result=start_free;
        start_free+=total_bytes;
        return result;
    }else if(left_bytes>=size_n){
        std::cerr<<"内存池空间不够,但还可以提供一个或一个以上的区块空间\n";
        nobjs=left_bytes/size_n;
        total_bytes=size_n*nobjs;
        result=start_free;
        start_free+=total_bytes;
        return result;

    }else{
        std::cerr<<"一个区块都无法提供\n";
        size_t bytes_to_get=2*total_bytes+UP_TO_EIGHT(heap_size>>4);
        //试着让内存池把残余零头提供出来
        if(left_bytes>0){
            //内存池还有零头
            obj *volatile *my_free_list=free_list+FREELIST_INDEX(left_bytes);
            ((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) printf(bad_alloc);
        heap_size+=bytes_to_get;
        end_free=start_free+bytes_to_get;
        return(chunk_alloc(size_n,nobjs));
    }

}
void *allcate::refill(size_t n){
    int nobjs=20,i;
    std::cerr<<"从内存池调"<<n*nobjs<<"内存\n";
    char *chunk=chunk_alloc(n,nobjs);
    obj *volatile *my_free_list;//作为free_list某种意义上的迭代器
    obj *result;//结果节点
    //方便遍历的中间变量
    obj *current_obj,*next_obj;
    //如果申请到一个区块就分配这个区块给客端
    if(1==nobjs) return((obj*)chunk);
    //否则调整free——list 纳入新节点(chunk申请到足够的区块)
    my_free_list=free_list+FREELIST_INDEX(n);
    //把第一块给客端
    result=(obj*)chunk;
    //引导free list指向新配置的空间(取自内存池)
    *my_free_list=next_obj=(obj *)(chunk+n);
    //free list的各节点连接起来
    for(i=1;;i++){//从1开始,0个给了客端
        current_obj=next_obj;
        next_obj=(obj*)((char *)next_obj+n);
        if(nobjs-1==i){
            current_obj->free_list_link=0;
            break;
        }else{
            current_obj->free_list_link=next_obj;

        }

    }
    return (result);
}
void *allcate::alloc(size_t n){
    obj *volatile *my_free_list;
    obj *result;
    std::cerr<<"调用alloc函数申请"<<n<<"大小空间\n";
    if(n>128){
        std::cerr<<"大于128直接调malloc\n";
        void* result=malloc(n);
        if(0==result) printf(bad_alloc);
        else return result;
    }
    //16个链表中寻找合适的自由链表
    my_free_list=free_list+FREELIST_INDEX(n);
    result=*my_free_list;
    if(0==result){
        std::cerr<<"没有可用free_list,refill函数填充链表\n";
        void *r=refill(UP_TO_EIGHT(n));
        return r;
    }
    std::cerr<<"有可用的free_list直接使用\n";
    *my_free_list=result->free_list_link;
    return result;
}
void allcate::dealloc(void *p,size_t n){
    obj *q =(obj *)p;
    obj * volatile *my_free_list;
    //大于123就调用第一级配置器
    if(n>128){
        std::cerr<<"调用第一级配置器大小为"<<n<<"内存free回收\n";
        free(p);
        return;
    }
    std::cerr<<"调用第二级配置器回收大小为"<<n<<"内存\n";
    my_free_list=free_list+FREELIST_INDEX(n);
    q->free_list_link=*my_free_list;
    *my_free_list=q;
}
size_t allcate::left(){
    std::cerr<<"内存池剩余"<<end_free-start_free<<"大小空间\n";
    return end_free-start_free;
}
#endif // ALLOCATE_H_INCLUDED

上面是头文件
下面是调试

#include<bits/stdc++.h>
#include"allocate.h"
using namespace std;
int main(){
    allcate a;
    void *p=a.alloc(8);
    a.left();
    void *h=a.alloc(64);
    a.dealloc(h,64);
    a.left();
    void *n=a.alloc(8);
    a.left();
    return 0;
}

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值