基于C语言的内存池实现

前言

1、池化技术 :简单点来说,就是提前保存大量的资源,以备不时之需

        对于线程,内存,oracle的连接对象等等,这些都是资源,程序中当你创建一个线程或者在堆上申请一块内存时,都涉及到很多系统调用,也是非常消耗CPU的,如果你的程序需要很多类似的工作线程或者需要频繁的申请释放小块内存如果没有在这方面进行优化,那很有可能这部分代码将会成为影响你整个程序性能的瓶颈。

池化技术主要有线程池,内存池,连接池,对象池等等。

一、内存池

1、内存池原理

        内存池(Memory pool)提供了一种比较可行的解决方案。首先是创建内存池。这个过程的主要任务是预先分配足够大的内存,形成一个初步的“内存池”。分配内存,也就是用户请求内存时,会返回内存池中一块空闲的内存,并将其标志置为已使用,当然具体细节和方法有很多。释放内存时,不是真正地调用free或是delete的过程,而是把内存放回内存池的过程。在把内存放入内存池的同时,要把标志位置为空闲。最后在应用程序结束时,要把内存池销毁。这里主要做的工作就是把内存池中的每一块内存释放。

2、使用内存池的好处

        设计内存池的目标是为了保证代码长时间高效的运行,通过对申请空间小而申请频繁的对象进行有效管理,减少内存碎片的产生,合理分配管理用户内存,从而减少系统中出现有效空间足够,而无法分配大块连续内存的情况。

  • 减少了内存碎片的产生。这个可以从创建内存池的过程中看出。我们在创建内存池时,分配的都是一块块比较整的内存块,这样可以减少内存碎片的产生;
  • 提高了内存的使用效率。这个可以从分配内存和释放内存的过程中看出。每次的分配与释放并不是去调用系统提供的函数或是操作符去操作实际的内存,而是在复用内存池中的内存。

3、缺点

就是很有可能会造成内存的浪费,原因也很明显,开始分配了一大块内存,不是全部都用得到的。

4、内存池的代码实现

内存池代码实现原理图

 4.1、内存池结构体

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define MP_ALIGNMENT       		32		//对齐大小
#define MP_PAGE_SIZE			4096	//内存池小块大小
#define MP_MAX_ALLOC_FROM_POOL	(MP_PAGE_SIZE-1)

#define mp_align(n, alignment) (((n)+(alignment-1)) & ~(alignment-1))
#define mp_align_ptr(p, alignment) (void *)((((size_t)p)+(alignment-1)) & ~(alignment-1))

typedef struct mp_large_s {
	struct mp_large_s *next;    //下一块 内存大块
	void *alloc;                //内存大块的地址
}mp_large_t;

typedef struct mp_node_s {

	unsigned char *last;        //当前 内存小块已分配的地址
	unsigned char *end;         //内存小块 末尾地址
	
	struct mp_node_s *next;     //指向下一块 内存小块
	size_t failed;              //5次访问节点还是不可以分配空间就访问下一个节点
}mp_node_t;

typedef struct mp_pool_s {

	size_t max;				// 小块内存 的最大值

	mp_node_t *current;		//指向当前可分配的 内存小块
	mp_large_t *large;      //指向 内存大块

	mp_node_t head[0];      //内存小块 开始分配的地址

}mp_pool_t;

4.2 内存池函数封装

mp_pool_t *mp_create_pool(size_t size);            //内存池创建
void mp_destory_pool(mp_pool_t *pool);             //内存池删除
void *mp_alloc(mp_pool_t *pool, size_t size);      //内存池分配
void *mp_nalloc(mp_pool_t *pool, size_t size);     //内存池分配
void *mp_calloc(mp_pool_t *pool, size_t size);     //内存池分配
void mp_free(mp_pool_t *pool, void *p);            //内存池释放
void mp_reset_pool(mp_pool_t *pool) ;              //内存池重置

4.3 内存池测试代码

mp_pool_t *mp_create_pool(size_t size) {

	mp_pool_t *p;
	int ret = posix_memalign((void **)&p, MP_ALIGNMENT, size + sizeof(mp_pool_t) + sizeof(mp_node_t));
	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(mp_pool_t) + sizeof(mp_node_t);
	p->head->end = p->head->last + size;

	p->head->failed = 0;

	return p;

}

void mp_destory_pool(mp_pool_t *pool) {

	mp_node_t *h, *n;
	mp_large_t *l;

	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			free(l->alloc);
		}
	}

	h = pool->head->next;

	while (h) {
		n = h->next;
		free(h);
		h = n;
	}

	free(pool);

}

//内存池重置 释放large 将node节点last重置
void mp_reset_pool(mp_pool_t *pool) {

	mp_node_t *h;
	mp_large_t *l;

	for (l = pool->large; l; l = l->next) {
		if (l->alloc) {
			free(l->alloc);
		}
	}

	pool->large = NULL;

	for (h = pool->head; h; h = h->next) {
		h->last = (unsigned char *)h + sizeof(mp_node_t);
	}

}

//内存池小块分配
static void *mp_alloc_block(mp_pool_t *pool, size_t size) {

	unsigned char *m;
	mp_node_t *h = pool->head;
	size_t psize = (size_t)(h->end - (unsigned char *)h);
	
	int ret = posix_memalign((void **)&m, MP_ALIGNMENT, psize);
	if (ret) return NULL;

	mp_node_t *p, *new_node, *current;
	new_node = (mp_node_t*)m;

	new_node->end = m + psize;
	new_node->next = NULL;
	new_node->failed = 0;

	m += sizeof(mp_node_t);
	m = mp_align_ptr(m, MP_ALIGNMENT);
	new_node->last = m + size;

	current = pool->current;

	for (p = current; p->next; p = p->next) {
		if (p->failed++ > 4) { //
			current = p->next;
		}
	}
	p->next = new_node;

	pool->current = current ? current : new_node;

	return m;

}

//内存池大块分配
static void *mp_alloc_large(mp_pool_t *pool, size_t size) {

	void *p = malloc(size);
	if (p == NULL) return NULL;

	size_t n = 0;
	mp_large_t *large;
	for (large = pool->large; large; large = large->next) {
		if (large->alloc == NULL) {
			large->alloc = p;
			return p;
		}
		if (n ++ > 3) break;
	}

	large = mp_alloc(pool, sizeof(mp_large_t));
	if (large == NULL) {
		free(p);
		return NULL;
	}

	large->alloc = p;
	large->next = pool->large;
	pool->large = large;

	return p;
}

void *mp_memalign(mp_pool_t *pool, size_t size, size_t alignment) {

	void *p;
	
	int ret = posix_memalign(&p, alignment, size);
	if (ret) {
		return NULL;
	}

	mp_large_t *large = mp_alloc(pool, sizeof(mp_large_t));
	if (large == NULL) {
		free(p);
		return NULL;
	}

	large->alloc = p;
	large->next = pool->large;
	pool->large = large;

	return p;
}

void *mp_alloc(mp_pool_t *pool, size_t size) {

	unsigned char *m;
	mp_node_t *p;

	if (size <= pool->max) {

		p = pool->current;

		do {
			
			m = mp_align_ptr(p->last, MP_ALIGNMENT);
			if ((size_t)(p->end - m) >= size) {
				p->last = m + size;
				return m;
			}
			p = p->next;
		} while (p);

		return mp_alloc_block(pool, size);
	}

	return mp_alloc_large(pool, size);
	
}


void *mp_nalloc(mp_pool_t *pool, size_t size) {

	unsigned char *m;
	mp_node_t *p;

	if (size <= pool->max) {
		p = pool->current;

		do {
			m = p->last;
			if ((size_t)(p->end - m) >= size) {
				p->last = m+size;
				return m;
			}
			p = p->next;
		} while (p);

		return mp_alloc_block(pool, size);
	}

	return mp_alloc_large(pool, size);
	
}

void *mp_calloc(mp_pool_t *pool, size_t size) {

	void *p = mp_alloc(pool, size);
	if (p) {
		memset(p, 0, size);
	}

	return p;
	
}

void mp_free(mp_pool_t *pool, void *p) {

	mp_large_t *l;
	for (l = pool->large; l; l = l->next) {
		if (p == l->alloc) {
			free(l->alloc);
			l->alloc = NULL;

			return ;
		}
	}
	
}


int main(int argc, char *argv[]) {

	int size = 1 << 12;
	int size1 = 1 << 3;
	int size2 = 1 << 6;
	int size3 = 1 << 9;
	mp_pool_t *p = mp_create_pool(size);

	int i = 0;
	for (i = 0;i < 10;i ++) {

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

	//printf("mp_create_pool: %ld\n", p->max);
	printf("mp_align(123, 32): %d, mp_align(17, 32): %d\n", mp_align(24, 32), mp_align(17, 32));
	//printf("mp_align_ptr(p->current, 32): %lx, p->current: %lx, mp_align(p->large, 32): %lx, p->large: %lx\n", mp_align_ptr(p->current, 32), p->current, mp_align_ptr(p->large, 32), p->large);

	int j = 0;
	for (i = 0;i < 5;i ++) {

		char *pp = mp_calloc(p, 32);
		for (j = 0;j < 32;j ++) {
			if (pp[j]) {
				printf("calloc wrong\n");
			}
			printf("calloc success\n");
		}
	}

	//printf("mp_reset_pool\n");

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

	mp_reset_pool(p);

	//printf("mp_destory_pool\n");
	for (i = 0;i < 58;i ++) {
		mp_alloc(p, 256);
	}

	mp_destory_pool(p);

	return 0;

}

5、内存池库tcmalloc的使用

5.1 tcmalloc安装

        tcmalloc在gperftools之中,故想要使用tcmalloc,就得先安装gperftools。在linux下,其安装步骤如下:

去github官网下载: http://​ https://github.com/gperftools/gperftools.git ​ gperftools-master.zip

环境配置:

编译环境:Ubuntu 

编译器:arm-fsl-linux-gnueabi

指定安装路径:/home/thunder/Downloads/gperftools-master/build

cd gperftools-master

./autogen.sh 

默认安装

./configure --enable-frame-pointers

指定安装

./configure --prefix=/home/thunder/Downloads/gperftools-master/build --host=arm-fsl-linux-gnueabi --enable-frame-pointers

sudo make

sudo make install

执行上面命令后会生成下面4个文件

 5.2 tcmalloc的使用

只要在编译代码时添加 -ltcmalloc就可以了。

gcc -o main main.cc -L. -ltcmalloc

这样编译出来的可执行程序main使用的malloc和free将来自tcmalloc。

补充:类似的内存池的库还有Jemalloc

完!

如过文章对您有帮助,请点赞一下吧

4

444内存池池的实现内存池的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值