Skip to content

Latest commit

 

History

History
208 lines (71 loc) · 5.16 KB

【NO.530】Linux服务器开发,内存池原理与实现.md

File metadata and controls

208 lines (71 loc) · 5.16 KB

【NO.530】Linux服务器开发,内存池原理与实现

0.前言

内存池顾名思义,是管理栈空间中堆的组件。有了内存池,可以避免频繁的分配和释放堆空间。从另一个角度说,内存池是为了提升变量的生存周期。

1.作用

频繁分配导致内存分配碎片化。 内存管理不是几分钟几天的内存问题,而是解决当程序长时间运行时,改变资源不进行管理造成被系统杀死的命运。如果运行几个月后偶现的问题较难排查,对于这种问题排查也是束手无策,所以使用内存池是一件非常有必要的事。

2.注意点

  • 一定要用内存池。

  • 不要自己实现内存池!听到这一点我就开心了,毕竟减少了时间劳动的成本。因为这种组件很大部分都工程师都没有这个能力。

  • 内存池的原理一定要懂。

    jemallocl是c实现的,tcmaloc是google用c++实现的,更推荐这个,内存回收机制有些小问题,绝大部分使用没问题。用起来简单,加个宏定义,会hook住malloc。

    在这里插入图片描述

    小块回收是一个极其麻烦的事情,随着时间的推移小字节内存块越来越多浪费也越来越多。解决方案是固定大小的内存。但是固定大小的也存在着不灵活的问题,很多内存用不了的情况。

    改进的方法使用梯度的固定大小,大块的内存要多少给多少,小块内存分档次进行处理。

    在这里插入图片描述

    但是仍存在的问题时:

  • 链表查找速度慢。——>1、区分使用过否。2、红黑树,哈希。

  • 出现了间隙,不利于回收,极其麻烦。——>影响小块的回收。

几种使用场景 1、全局内存池 jemmaloc/tcmalloc。 2、一个连接做一个内存池,一个连接释放一个内存池被销毁。生命周期短所以小块不用回收。 3、消息x,浪费。

3.实现内存池

使用大块和小块来实现。

void *mp_memalign(struct mp_pool_s *pool, size_t size, size_t alignment)



 {



    void *p;



    //posix_memalign()这个函数可以分配出大空间的内存



    int ret = posix_memalign(&p, alignment, size);



    if (ret) {



        return NULL;



    }



    struct mp_large_s *large = mp_alloc(pool, sizeof(struct mp_large_s));



    if (large == NULL) 



    {



        free(p);



        return NULL;



    }



    large->alloc = p;



    large->next = pool->large;



    pool->large = large;



 



    return p;



}
struct mp_pool_s *mp_create_pool(size_t size)



 {



    struct mp_pool_s *p;



    int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s));



    if (ret)



     {



        return NULL;



    }



    p->max = (size < MP_MAX_ALLOC_FROM_POOL) ? size : MP_MAX_ALLOC_FROM_POOL;



    p->current = p->head;



    p->large = NULL;



    p->head->last = (unsigned char *)p + sizeof(struct mp_pool_s) + sizeof(struct mp_node_s);



    p->head->end = p->head->last + size;



 



    p->head->failed = 0;



 



    return p;



}

posix_memallign((void **)&pool,ALIGNMENT,size+sizeof(struct mp_pool)); //分配超过4K就分配不出来,所有调用此api

注意释放顺序,必须大块先释放,再释放小块。将指向大块节点的那块内存放在小块中,可以减少释放内存时的难度系数。

4.总结

今天通过零声学院King老师绘声绘色的讲述内存池,让我感触颇深。 从技术知识层面,我又从新的一个角度认识了内存池。以前一直感觉内存池是一个臃肿的组件,从来没有感受到内存池存在着重要的意义。有了内存池就可以轻松避免内存管理出现的问题,有的程序工作几个月以上出现崩溃的情况,偶现的问题往往是极难排查的,用上内存池可以更加保险。尽管不需要自己手写内存池,但是我已经足够深入的了解了内存池的历史演变和工作原理,可以说这在工作中完全足够在同事面前炫耀一番了。 感觉这句话是我印象最深的:线程池、内存池其实没有标准,要根据实际情况去确定。个人理解没有标准往往比有标准更加痛苦,我只能通过自己的努力不断的探索标准,才能更快的进步。 最后,还是非常感谢零声学院的King老师,啊,有King老师的陪伴学习的路上变得异常平坦开阔。

原文作者:屯门山鸡叫我小鸡

原文链接:https://bbs.csdn.net/topics/604988800