栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

仿照nginx手写内存池

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

仿照nginx手写内存池

内存池能解的问题:解决频繁调用内存申请释放产生大量的内存碎片,从而导致内存分配失败,还可以降低内存申请的损耗。

我们实现的线程池按照内存的的页 4k大小分为 大块内存申请和小块内存申请(当然也可以按照你自己定义的大小来决定大小块儿的分配),在线程池初始化的时候我们会先分配一个小小块儿内存,至于大块儿内存我们先不管。

下面我们讲讲小块内存节点的数据结构

我们在来看看大块儿内存的分配如下图所示:

下面我们来定义这三种数据结构:

1.小块儿内存节点

struct mp_node_s{
    unsigned char *start;    //指向已用内存的末端
    unsigned char *end;        //指向整个小块儿内存的末端        
    struct mp_node_s * next;
    int flags;
}

2.大块儿内存节点

struct mp_large_s{
    struct mp_large_s *next;
    void *alloc;                         //指向分配的内存
}

3. 线程池数据结构

struct mp_pool_s{
    size_t max;                    //除了用户可以自定义大小块儿 我们程序自己也要有个限制
    struct mp_node_s *current;    //小块指针
    struct mp_large_s *large;    //大块儿指针
    struct mp_node_s head[0];
}

内存池的创建 
#define MP_ALIGNMENT 32        //对齐方式
#define MAX_ALLOC_BLOCK 4096 //小块

struct mp_pool_s * mp_create_pool(size_t size){
    struct mp_pool_s *p;
    int ret = posix_memalign(&p,MP_ALIGNMENT,size+sizeof(mp_pool_s)+sizeof(mp_node_s));
    if(ret ) return NULL;
    p->max = size < MAX_ALLOC_BLOCK ? size:MAX_ALLOC_BLOCK;
    p->current = p->head;
    p->large = NULL; //大块先不分配
    p->head->start = (unsigned char *)p+sizeof(mp_pool_s)+sizeof(mp_node_s);
    p->head->end =     p->head->start +size;//第一个块的end不会改变每次只是改变的start
    p->head->flag = 0;
    return p;
}

//调用这个函数申请内存--这里面区分分配大块还是小块内存用户不感知
void * mp_alloc(struct mp_pool_s*pool,size_t size){
    
    if(size <= pool->max) {
        
        struct mp_node_s *p = pool->current;
        do{
            unsigned char*m = p->start;
            if(p->end - p->start >=size){
                p->start += size;
                return m;
            }
            p = p->next; //往下找
        }while(p);
        
        return mp_alloc_block(pool,size);//没有足够的空间就分配一块内存
    }
    //分配大块
    return mp_alloc_large(pool,size);
}

 如上图所示:新分配的小块儿内存采用头部插入法

//原内存池小块儿内存没有足够的空间 则分配新的小块儿内存
static void* mp_alloc_block(struct mp_pool_s* pool,size_t size ){
    
    struct mp_node_s *h = pool->head;
    //分配一个小块儿 获取区分大小块儿内存临界值
    size_t psize = (size_t)(h->end - (unsigned char*)h);
    unsigned char * m = NULL;
    int ret = posix_memalign(&m,MP_ALIGNMENT,psize);
    if(ret)return NULL;
    //加入的内存池小块链表 插入表头
    struct mp_node_s * new_node = (struct mp_node_s*)m;
    new_node->next = pool->current;
    pool->current = new_node;
    pool->head = new_node;
    
    new_node->start = (unsigned char*)m+sizeof(mp_node_s)+size;
    new_node->end = (unsigned char*)m+sizeof(mp_node_s)+psize;
    
    return m+sizeof(mp_node_s);
}

大块儿内存分配函数
static void* mp_alloc_large(struct mp_pool_s* pool,size_t size ){
    void *p = NULL;
    int ret = posix_memalign(&p,MP_ALIGNMENT,size);
    struct mp_large_s*large = NULL;
    for(large = pool->large;large;large = large->next){
        if(large->alloc == NULL){
            large->alloc = p;
            return p;
        }
    }
}

内存池的销毁
void mp_destory_pool(struct mp_pool_s*pool){
    
    struct mp_large_s *l;
    for(l = pool->large;l;l = l->next){
        if(l->alloc)
            free(l->alloc);
    }
    //小块释放
    struct mp_node_s*n, *h = pool->head->next;
    while(h){
        n = h->next;
        free(h);
        h = n;
    }
    free(pool);
}

释放内存 只对大块儿内存进行释放
void mp_free(struct mp_pool_s* pool,void* p){
    
    struct mp_large_s *l;
    for (l = pool->large; l; l = l->next) {
        if (p == l->alloc) {
            free(l->alloc);
            l->alloc = NULL;

            return ;
        }
    }
}

测试函数
int main()
{
    int size = 1 << 12;
    struct mp_pool_s *p = mp_create_pool(size);
    int i = 0;
    for (i = 0;i < 10;i ++) {

        void *mp = mp_alloc(p, 512);
    }

    for (i = 0;i < 5;i ++) {
        void *l = mp_alloc(p, 8192);
        mp_free(p, l);
    }
    mp_destory_pool(p);
    return 0;
}
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/323632.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号