Linux(服务器编程):36---C/C++内存池设计(仿Nginx内存池设计)

一、内存池概述

  • 服务器会频繁地对内存进行申请和释放,频繁地操作将带来如下的缺点:
    • 服务器性能降低,因为需要频繁地申请和释放内存
    • 内存碎片化多
    • 等等......
  • 市场上开源的比较好用的内存池有:
    • tcmalloc:MySQL使用的
    • jemalloc:Tomcat使用的
    • Nginx也有一套自己的内存池(本文就是仿照Nginx的内存池设计的)

二、内存池设计

  • 因为内存页的大小为4K,因此在设计内存池的时候,我们将认为:
    • <4k的内存:称为小内存块
    • >4K的内存:称为大内存快

struct mp_large_s(大内存块结构)

  • 当我们申请的内存大于4K时,就会申请一个大的内存块,这个结构体就是大内存结构
  • 该结构不是真正存储内存的,真正的内存是由其alloc成员所指向的
  • 如上结构图所示(蓝色部分):
    • alloc:指向真正的大内存块地址
    • next:指向下一个struct mp_large_s结构的指针
//大内存块节点
struct mp_large_s {
    void *alloc;             //指向该大内存快的实际存储区域
    struct mp_large_s *next; //指向下一块大内存快
};

struct mp_node_s(大内存块结构)

  • 当我们申请的内存小于4K时,就会申请一个小的内存块,这个结构体就是小内存结构
  • 与struct mp_large_s结构一样,该结构不是真正存储内存的,真正的内存是在结构后面的data区域存储的
  • 如上结构图所示(蓝色部分):
    • last:指向后面data区域中可用内存的起始地址
    • end:指向后面data区域最后的指针
    • next:指向下一个struct mp_node_s结构的指针
    • failed:表示当前内存块是否停止使用
//小内存块节点
struct mp_node_s {
    unsigned char *last;     //后面数据存储区域中可用区域的起点
    unsigned char *end;      //后面数据存储区域的终点
    
    struct mp_node_s *next;  //指向下一块小内存块
    
    int failed;              //该内存块是否不再使用
};

struct mp_pool_s(内存池)

  • 该结构是内存池的真正结构,我们操作内存池时就是操作这个结构
  • 如上结构图所示(蓝色部分):
    • max:区别大内存块与小内存块的界值,上面我们提到过了,我们本案例以4K为例
    • current:指向小内存块链表的起点
    • large:指向大内存块链表的起点
    • head[0]:柔性数组,struct mp_node_s head[0]相当于struct mp_node_s *head。用来指向于current链表中的第一个struct mp_node_s节点,通过这个成员可以方便的操作current链表
//内存池,管理者所有的内存块
struct mp_pool_s {
    //区别大内存块与小内存块的界值: <max的用struct mp_node_s表示, >max的用struct mp_large_s表示
    int max;

    struct mp_node_s  *current; //管理小内存块的链表起点
    struct mp_large_s *large;   //管理大内存快的链表起点

    //柔型数组: head[0]指向current链表第1个节点, head[1]指向current链表第2个节点...以此类推
    //用这个数组来操作每个mp_node_s节点相关指标(比如更改last等),不需要再去遍历
    struct mp_node_s head[0];
};

三、内存池接口设计

  • 下面是内存池的相关接口

四、代码实现

五、运行效果

  • 该代码正在修正,最近几天完成

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/106627263