【项目】C++高并发内存池

一、项目介绍

        当前项⽬是实现⼀个⾼并发的内存池,他的原型是google的⼀个开源项⽬tcmalloc,tcmalloc全称 Thread-Caching Malloc,即线程缓存的malloc,实现了⾼效的多线程内存管理,⽤于替代系统的内 存分配相关的函数(malloc、free)。

tcmalloc源代码

        这个项⽬会⽤到C/C++、数据结构(链表、哈希桶)、操作系统内存管理、单例模式、多线程、互斥锁 等等⽅⾯的知识。

1、池化技术

  • 所谓池化技术,就是程序先向系统申请过量的资源,然后自己管理,当程序中需要申请内存时,不是直接向操作系统申请,而是直接从内存池中获取,释放内存时也不是将内存返回给操作系统,而是返回内存池中。

  • 因为每次申请该资源都有较大的开销,这样提前申请好了,使用时就会非常快捷,能够大大提高程序运行效率。

  • 在计算机中有很多使用这种池技术的地方,例如线程池、连接池等。

  • 以服务器上的线程池为例,它的主要思想是:先启动若⼲数量的线程,让它们处于睡眠状态,当接收到 客⼾端的请求时,唤醒池中某个睡眠的线程,让它来处理客⼾端的请求,当处理完这个请求,线程⼜进⼊睡眠状态。

2、主要解决的问题

        内存碎⽚分为外碎⽚和内碎⽚。外部碎⽚是⼀些空闲的连续内存区域太⼩,这些内存空间不连续,以⾄于合计的内存⾜够,但是不能满⾜⼀些的内存分配申请需求。内部碎⽚是由于⼀些对⻬的需求,导致分配出去的空间中⼀些内存⽆法被利⽤。

3、malloc

  • C++中动态申请内存都是通过malloc去申请的,但实际上我们并不是直接去堆中获取内存的,而malloc就是一个内存池。
  • malloc() 相当于向系统 “批发” 了一块较大的内存空间,然后“零售” 给程序使用,当全部使用完或者程序有大量内存需求时,再根据需求向操作系统申请内存。

⼀⽂了解,Linux内存管理,malloc、free 实现原理

二、定长内存池设计

1、开辟内存

  • 使用malloc开辟一大块内存,让_memory指针指向这个大块内存
  • _memory 设置为char* 类型,是为了方便切割时_memory向后移动多少字节数。

2、申请内存

  • 将_memory强转为对应类型,然后赋值给对方,_memory指针向后移动对应字节数即可。
  • 如果有存在已经切割好的小块内存,则优先使用小块内存。

3、释放内存

  • 用类型链表的结构来进行存储。
  • 用当前小块内存的头4字节存储下一个小块内存的地址,最后用_freeList指针指向第一个小块内存的地址(并不是将内存释放给操作系统)
  • 所以开辟内存时,开辟的内存大小必须大于或等于一个指针类型的大小。

4、向堆申请页为单位的大块内存

5、代码实现

#ifdef _WIN32		//如果32位则包含头文件
    #include<windows.h>
#else
    //
#endif

//定长内存池
//template<size_t N>
//class ObjectPool
//{};

// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
	//         参数: 分配的区域的起始地址,区域的大小(字节),分配的类型,内存保护
	void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	// kpage << 13 以页为单位进行内存分配
#else
	// linux下brk mmap等
#endif

	if (ptr == nullptr)
		throw std::bad_alloc();

	return ptr;
}

template<class T>
class ObjectPool
{
public:
	T* New()
	{
		T* obj = nullptr;
		//优先利用还回来的内存
		if (_freeList)
		{
			void* next = *((void**)_freeList);	//转为void**类型,变为下一个结点的指针
			obj = (T*)_freeList;
			_freeList = next;
		}
		else {
			//剩余内存不够一个大小时重新开大块空间
			if (_remainBytes < sizeof(T))
			{
				_remainBytes = 128 * 1024;
				//_memory = (char*)malloc(_remainBytes);
				_memory = (char*)SystemAlloc(_remainBytes >> 13);  //_remainBytes >> 13 单位从字节数转换为页数
				if (_memory == nullptr)
				{
					throw std::bad_alloc();
				}
			}

			obj = (T*)_memory;
			//根据编译器确定指针类型大小
			size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
			_memory += objSize;			//后移一个指针的大小指向实际的内存块
			_remainBytes -= objSize;	//实际内存大小
		}
		//定位new,显示调用T的构造函数初始化
		new(obj)T;

		return obj;
	}

	vo
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值