内存池--伙伴算法的实践

内存池主要分为三个部分:class buffer_t,class bufferpool_t,class mempool_t

1.class mempool_t:内存开辟与释放的接口,既可以通过内存池开辟释放或者在超过内存池最大内存分配大小时,通过系统进行开辟与释放。

2.class bufferpool_t:在mempool_t中申请的实际内存大小2^n(2^n<=最大内存分配大小)内存池)对应于一个bufferpool_t,一个bufferpool_t由list链表来管理多个2^n大小的内存块

3.class buffer_t:对实际内存块进行管理与存储。

话不多说,直接上源代码。

class mempool_t:

#include "bufferpool_t.h"
class mempool_t
{
public:
	static mempool_t *get_instance();

	/*
		申请内存
		@param uint32_t size_ 内存大小
			   如果size_ 大与max_alloc_size 将重系统请求内存
	*/
	void *alloc(uint32_t size_);

	/*
		释放内存
		@param void* 内存句柄
	*/
	bool free(void* ptr);

	/*
	配置内存池最大内存分配大小
		@param uint32_t max_alloc_size.
		如果 mempool_t.alloc (size):其中 size > max_alloc_size
		内存池将重系统分配内存,但是 释放的时候 也一定要调用
		mempool_t.free 来释放,否则会内存错误
	*/
	void config(const uint32_t &max_alloc_size = 1<<20);

private:
	mempool_t(void);
	~mempool_t(void);
	typedef std::map<uint32_t ,bufferpool_t *> bufferpool_set_t;
	bool get_bufferpool_size( uint32_t size_, uint32_t &buf_size_ );

	/*向系统请求分配内存
	  @param uint32_t size_ 内存大小
	  @return void* 内存句柄
	*/
	void * internal_malloc( const uint32_t &size_ );

	/*直接释放内存
	  @param void *ptr_ 内存句柄
	  @return bool true成功, false失败,原因是内存不是internal_malloc返回的,
	  或是内存已经被破坏了*/
	bool internal_free(void *ptr_);

	bufferpool_set_t bufferpool_set;
	uint32_t max_alloc_size;
	std::mutex bufferpool_set_mutex;

};
#include "stdafx.h"
#include "mempool_t.h"
mempool_t::mempool_t(void)
	:max_alloc_size(1<<20)//1MB
{

}
mempool_t::~mempool_t(void)
{
	while (bufferpool_set.empty()==false)
	{
		bufferpool_t *bufferpool = bufferpool_set.begin()->second;
		bufferpool_set.erase(bufferpool_set.begin());
		delete bufferpool;
	}
}
//设置内存分配对象的实例
mempool_t * mempool_t::get_instance()
{
	static mempool_t *instance = new mempool_t;
	return instance;
}
void * mempool_t::alloc( uint32_t size_ )
{
	uint32_t buf_size;
	void *buf;
	bool rc = get_bufferpool_size(size_,buf_size);
	if (rc)
	{
		bufferpool_t *bufferpool;

		std::lock_guard<std::mutex> lock_guard(bufferpool_set_mutex);
		bufferpool_set_t::iterator it = bufferpool_set.find(buf_size);

		if (it == bufferpool_set.end ())
		{
			bufferpool = new bufferpool_t(buf_size);
			bool rc = bufferpool_set.insert (
				bufferpool_set_t::value_type(buf_size,bufferpool)).second;
			assert(rc);
		}
		else
		{
			bufferpool = it->second;
		}
		buf =(void*) bufferpool->alloc_buffer ();
	}
	else
	{
		buf = internal_malloc(size_);
	}
	return buf;
}

bool mempool_t::free( void* ptr )
{
	uint32_t data_size;
	bool rc = bufferpool_t::get_buffer_size ((char*)ptr,data_size);
	if (rc)
	{
		std::lock_guard<std::mutex> lock_guard(bufferpool_set_mutex);

		bufferpool_t *bufferpool;
		bufferpool_set_t::iterator it = bufferpool_set.find(data_size);
		if (it == bufferpool_set.end ())
		{
			assert(false);
		}
		bufferpool = it->second;
		return bufferpool->free_buffer ((char*)ptr);;
	}
	else
	{
		return internal_free (ptr);
	}
	return false;
}

bool mempool_t::internal_free( void* ptr_)
{
	char *buf = (char*)ptr_ - sizeof(uint32_t);
	uint32_t size = *(uint32_t*)buf;
	if (size > max_alloc_size)
	{
		uint32_t tail_size = *(uint32_t*)((char*)ptr_ + size);
		if (tail_size == size)
		{
			delete buf;
			return true;
		}
	}
	return false;
}

bool mempool_t::get_bufferpool_size( uint32_t size_, uint32_t &buf_size_ )
{
	if (size_ > max_alloc_size) {
		return false;
	}
		/*
			求整数的最接近2的幂,
			向上对齐
		*/
		size_ = size_ - 1;
		size_ = size_ | (size_ >> 1);
		size_ = size_ | (size_ >> 2);
		size_ = size_ | (size_ >> 4);
		size_ = size_ | (size_ >> 8);
		size_ = size_ | (size_ >>16);
		size_ = size_ + 1;
		/*判断是否是2的幂*/
		if(0 != (size_&(size_-1)))
		{
			assert(false);
		}
		buf_size_ = size_;
		return true;
}

void * mempool_t::internal_malloc( const uint32_t &size_ )
{
	uint32_t buf_size = size_ + sizeof(uint32_t)*2;
	void *buf = malloc (buf_size);
	*(uint32_t*)buf = size_;
	*(uint32_t*)((char*)buf + sizeof(uint32_t)+size_) = size_;
	return ((char*)buf+sizeof(uint32_t));
}

void mempool_t::config( const uint32_t &max_buffer_size_ )
{
	max_alloc_size = max_buffer_size_;
}

class
bufferpool_t:

#include "buffer_t.hpp"
class bufferpool_t
{
public:
	bufferpool_t(const uint32_t &buffer_size_,const uint32_t &limit_size_ = 20);
	~bufferpool_t(void);
	 char *alloc_buffer();
	 bool free_buffer(char *buffer_);
	 static bool get_buffer_size(char *buffer_, uint32_t &buffer_size_);
private:
	typedef std::list<buffer_t*> buffer_list_t;

	buffer_list_t buffer_list;

	//buffer 类型大小,一个bufferpool_t只管理
	//同样大小的内存
	uint32_t buffer_type_size;

	//空闲内存最大数量
	uint32_t limit_buffer_list_size;
	//获取内存次数
	uint32_t alloc_times;
	//释放内存次数
	uint32_t free_times;
};
#include "stdafx.h"
#include "bufferpool_t.h"

bufferpool_t::bufferpool_t(const uint32_t &buffer_size_,const uint32_t &limit_size_)
{
	buffer_type_size = buffer_size_;
	limit_buffer_list_size = limit_size_;
	free_times = 0;
	alloc_times = 0;
}

bufferpool_t::~bufferpool_t(void)
{
	buffer_t *buffer;
	while (buffer_list.empty () == false)
	{
		buffer = buffer_list.front ();
		buffer_list.pop_back ();
		buffer->relase_buffer();
	}
}

char * bufferpool_t::alloc_buffer()
{
	buffer_t *buffer;
	char *buf;

	if (buffer_list.empty ())
	{
		char *buf = new char[buffer_type_size+sizeof(buffer_t)];
		buffer = new (buf)buffer_t(buffer_type_size,buf);
		//添加成员
	}
	else
	{
		buffer = buffer_list.front ();
		buffer_list.pop_front ();
	}
	++alloc_times ;
	buf = buffer->buf ();
	buffer->use (true);
	return buf;
}

bool bufferpool_t::free_buffer( char * buffer_)
{
	buffer_t *buffer = (buffer_t*)(buffer_ - sizeof(buffer_t));
	if (buffer->check_code () &&  buffer->length () == buffer_type_size)
	{
		if(buffer_list.size () < limit_buffer_list_size)
		{
			buffer->use (false);
			buffer_list.push_back (buffer);
			++free_times;
			return true;
		}
		else
		{
			buffer->relase_buffer();
			return true;
		}
	}
	return false;
}

bool bufferpool_t::get_buffer_size( char *buffer_ ,uint32_t &buffer_size_)
{
	buffer_t *buffer = (buffer_t*)(buffer_ - sizeof(buffer_t));
	if (buffer->check_code () &&
		buffer->use()&&
		buffer->buf () == buffer_)
	{
		buffer_size_ = buffer->length ();
		return true;
	}
	else
	{
		return false;
	}
}

class buffer_t:

#pragma once
#include "stddef.hpp"
class buffer_t
{
public:
	inline buffer_t(uint32_t length_, char *data_buf_)
	{
		buf_code = 0xbeaf;
		buf_length = length_;
		buf_data = data_buf_;
	}
	inline void relase_buffer(void)
	{
		delete []buf_data;
	}
	inline bool check_code()
	{
		return buf_code == 0xbeaf;
	}
	inline char *buf()
	{
		return buf_data+sizeof(*this);
	}
	inline uint32_t length()
	{
		return buf_length;
	}
	inline bool use()
	{
		return is_use;
	}
	inline void use(const bool &is_use_)
	{
		is_use = is_use_;
	}
private:
	char *buf_data;
	bool is_use;
	uint32_t buf_code;
	uint32_t buf_length;
};

写的不好的地方,请指出

时间: 2024-11-05 13:25:47

内存池--伙伴算法的实践的相关文章

berkeley db 内存池 LRU算法

priority based lru in src/mp/mp_fget.c, __memp_fget(), 初始化 一个page buffer时, 设置其 priority: bhp->priority = MPOOL_LRU_REDZONE; in src/mp/mp_fget.c, __memp_fput(), 对一个page buffer做put, 使其reference减一. bhp->ref--, 若reference减为0, 则调整其 priority. 下面的 bhp->

内存管理算法--Buddy伙伴算法【转】

转自:http://blog.csdn.net/orange_os/article/details/7392986 Buddy算法的优缺点: 1)尽管伙伴内存算法在内存碎片问题上已经做的相当出色,但是该算法中,一个很小的块往往会阻碍一个大块的合并,一个系统中,对内存块的分配,大小是随机的,一片内存中仅一个小的内存块没有释放,旁边两个大的就不能合并. 2)算法中有一定的浪费现象,伙伴算法是按2的幂次方大小进行分配内存块,当然这样做是有原因的,即为了避免把大的内存块拆的太碎,更重要的是使分配和释放过

内存管理算法--Buddy伙伴算法

Buddy算法的优缺点: 1)尽管伙伴内存算法在内存碎片问题上已经做的相当出色,但是该算法中,一个很小的块往往会阻碍一个大块的合并,一个系统中,对内存块的分配,大小是随机的,一片内存中仅一个小的内存块没有释放,旁边两个大的就不能合并.2)算法中有一定的浪费现象,伙伴算法是按2的幂次方大小进行分配内存块,当然这样做是有原因的,即为了避免把大的内存块拆的太碎,更重要的是使分配和释放过程迅速.但是他也带来了不利的一面,如果所需内存大小不是2的幂次方,就会有部分页面浪费.有时还很严重.比如原来是1024

内存池技术介绍(图文并茂,非常清楚)

看到一篇关于内存池技术的介绍文章,受益匪浅,转贴至此. 原贴地址:http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html 6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的内存.例如在程序中维护一个链表的数据结构时,每次新增或者删除一个链表的节点,都需要从内存堆上分配或者释放一定的内存:在维护一个动态数组时,如果动态数组的

内存池技术的原理与实现

6.1 自定义内存池性能优化的原理 如前所述,读者已经了解到"堆"和"栈"的区别.而在编程实践中,不可避免地要大量用到堆上的内存.例如在程序中维护一个链表的数据结构时,每次新增或者删除一个链表的节点,都需要从内存堆上分配或者释放一定的内存:在维护一个动态数组时,如果动态数组的大小不能满足程序需要时,也要在内存堆上分配新的内存空间. 6.1.1 默认内存管理函数的不足 利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的

详谈内存管理技术(二)、内存池

嗯,这篇讲可用的多线程内存池. 零.上期彩蛋:不要重载全局new 或许,是一次很不愉快的经历,所以在会有这么一个"认识".反正,大概就是:即使你足够聪明,也不要自作聪明:在这就是不要重载全局new,无论你有着怎样的目的和智商.因为: class XXX{ public: XXX* createInstance(); }; 这是一个不对称的接口:只告诉了我们如何创建一个[堆]对象,但是释放呢??! 很无奈,只能假设其使用全局默认的delete来删除(除此之外,没有其他选择):这时,我为了

基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

重写boost内存池

最近在写游戏服务器网络模块的时候,需要用到内存池.大量玩家通过tcp连接到服务器,通过大量的消息包与服务器进行交互.因此要给每个tcp分配收发两块缓冲区.那么这缓冲区多大呢?通常游戏操作的消息包都很小,大概几十字节.但是在玩家登录时或者卡牌游戏发战报(将整场战斗打完,生成一个消息包),包的大小可能达到30k或者更大,取决于游戏设定.这些缓冲区不可能使用glibc原始的new.delete来分配,这样可能会造成严重的内存碎片,并且效率也不高. 于是我们要使用内存池.并且是等长内存池,即每次分配的内

[原创]loki库之内存池SmallObj

loki库之内存池SmallObj 介绍 loki库的内存池实现主要在文件smallobj中,顾名思义它的优势主要在小对象的分配与释放上,loki库是基于策略的方法实现的,简单的说就是把某个类通过模板参数传递给主类,比如某个对象的创建可以通过不同的创建策略进行创建,本文主要讲loki的大致实现. smallobj层次 loki.smallobj主要分四层: 应用层smallobject,重载了operator new 和operator delete,内存通过底层获取 内存分配smallobjA