Linux(服务器编程3.3):---内存池设计(仿Nginx内存池设计c实现)

一、线程池的引入

  • 服务器在高并发下,有大量的客户端连接时,服务器要解析客户端发来的数据,就需要频繁对内存进行申请和释放,使得服务器性能的降低和内存的碎片化增多。

  • 开源的比较好用的内存池有:

    • 1,tcmalloc:MySQL使用的 ;
    • 2,jemalloc:Tomcat使用的 ;
    • 3,Nginx实现的内存池。
      这里是仿照nginx实现的内存池;

二、内存池的设计

  • 我们该如何实现内存池?
    内存池是一个组件,做出来以后,提供API给别人使用,在此提一个组件实现的通用方法:

    • 1,宏定义来处理
    • 2,结构体定义出来,基础数据结构定义出来
    • 3,对应的函数,对外提供API
    • 4,测试函数
  • 1,首先我们实现基础数据的结构:

    • 小于等于4k的内存,我们称为小块内存;
    • 大于的内存,我们称为小块内存;
    • 管理大块内存与小块内存的组件数据结构-----内存池组件;
struct mp_large_s(大内存块结构)
	* 当我们申请的内存大于4K时,就会申请一个大的内存块,这个结构体就是大内存结构;
	* 该结构不是真正存储内存的,真正的内存是由其alloc成员所指向的内存
//大内存节点
struct mp_large_s{
	void *alloc;                //指向大块的内存
	struct mp_large_s *next;   //指向下一个struct mp_large_s结构的指针
};
struct mp_node_s(大内存块结构)
	* 当我们申请的内存小于4K时,就会申请一个小的内存块,这个结构体就是小内存结构;
	* 与struct mp_large_s结构一样,该结构不是真正存储内存的,真正的内存是在结构后面的data区域存储的;
//小内存块节点
struct mp_node_s{
	unsigned char *start;        // 后面数据存储区域中可用区域的起点
	unsigned char *end;          // 后面数据存储区域的终点
	
	struct mp_node_s *next;     // 内存不够的malloc一块,使用链表连接
	int failed;                 // 用来表示遍历使用的次数
};
struct mp_pool_s(内存池组件)
	* 该结构是内存池的真正结构,我们操作内存池时就是操作这个结构;这里使用了柔性数组head[0],可以自行百度下。
//内存池,管理者所有的内存块
struct mp_pool_s{
	size_t max;    					// 区别大内存块与小内存块的界值: <max的用struct mp_node_s表示, >max的用struct mp_large_s表示
	struct mp_node_s *current;      // 管理小内存块的链表起点
	struct mp_large_s *large;       //管理大内存快的链表起点
	//柔性数组,加一个标签
	struct mp_node_s head[0];   //柔型数组: head[0]指向current链表第1个节点, head[1]指向current链表第2个节点...以此类推
    							//用这个数组来操作每个mp_node_s节点相关指标(比如更改last等),不需要再去遍历
};
  • 2,内存池数据结构图如下(盗用了别人的图):
    在这里插入图片描述

三、内存池API设计

内存池API函数(注意:mp_free()函数只释放大内存。为了提高效率,小块内存是不释放的,直到内存池销毁掉,才释放):

//内存池初始化函数
struct mp_pool_s * mp_create_pool(size_t size);
//内存池销毁函数;mp_large_s指针未释放?并不是,因为mp_large_s内存从pool中分配,小块内存一起释放掉;
void mp_destroy_pool(struct mp_pool_s *pool);
//使用内存池申请内存(大块或者小块)
void *mp_alloc(struct mp_pool_s *pool, size_t size);
//使用内存池申请内存,并将申请的内存置0,使用mp_alloc()实现内存申请,使用memset封装了一层
void *mp_calloc(struct mp_pool_s * pool, size_t size);
//释放大内存,为了提高效率,小块内存是不释放的,直到内存池被销毁掉,才释放;
void mp_free(struct mp_pool_s *pool, void *p);
//内存池重置初始化状态
void mp_reset_pool(struct mp_pool_s * pool);

//内部函数
//小块内存申请函数,提供给mp_alloc()使用
static void *mp_alloc_block(struct mp_pool_s *pool, size_t size);
//大块内存申请函数,提供给mp_alloc()使用
static void *mp_alloc_large(struct mp_pool_s *pool, size_t size);

源码见: https://github.com/Fang-create/memory_pool.git

四、测试函数

使用内存池,申请内存和释放内存测试,见main函数,运行效果如下图。
在这里插入图片描述
在此,实现了一个内存池。如果要看内存池的具体使用,可以看看nginx的源码。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值