游戏服务器引擎的设计(五)内存管理

本文介绍了游戏服务器内存管理的实现,重点讨论了内存池的设计,包括小于128字节的内存通过内存池管理,大于128字节则使用系统分配。内存池分为16个链表,按8字节颗粒度分配内存。在DEBUG模式下,记录内存使用情况,便于定位问题和统计。此外,文章还提及了开源内存管理库如jemalloc的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++的程序都会对内存管理比较敏感,经常会发生内存泄漏的bug,同时为了内存的快速申请和释放,以及减少小块内存碎片,故大多都会有内存管理模块。

我在自己的服务器框架内加了内存管理,基本上是STL库的那一套,对小于128个字节的内存在内存池中管理申请和释放,而大于128的调用系统的内存申请及释放, 只不过在内部添加内存记录模块,当开启DEBUG标记的时候,会记录当前内存池总大小,已使用大小,和剩余大小。 需要检测或者查找申请记录的时候可以把当前内存情况输出到文件中。

// 这里简单讲下原理实现:

内存池中管理着128个字节以下的内存申请,如果大于128个字节的内存申请直接调用系统的malloc,如果小于128个字节就在内存池中申请。而内存池中维护着16个链表,每个链表里是已经申请分配好的内存块,他们的颗粒度是8字节,比如第一个链表里全部是8个字节大小的内存块,而第二个链表里都是16个字节的内存块,第三个链表里都是24个字节的内存块,以此类推直到128个字节就是第十六个链表。当业务层面要申请字节大小为1到8个的内存时,都会在第一个链表中把已经预分配好的内存节点取出来返回给业务层。 要申请大小为9到16的内存时就把第二个链表中取出一个节点分配出去。 而如果业务层释放内存的时候,就按照对应的大小插入的相应的链表中。如果链表空了,就从预先申请的一块大的内存中,再次分配N个相应大小的内存块插入到链表中。如果预先申请的大内存也分配完了,就再次调用系统的malloc 申请一块大内存。 所有的内存节点都是在这个大的内存块上分配的。这样避免了小块的内存碎片。

而DEBUG 模式开启的话,会在申请内存的时候记录申请的所在的文件,以及行号,用于排查问题,以及统计每个模块内存使用情况。

// 贴一下 :内存池头文件代码

// 8字节对齐(颗粒度)
	#define ALIGN 8

	// 在池中分配的最大大小
	#define MAX_SIZE 128

	// 内存池中类别个数 (MAX_SIZE / ALIGN)
	#define TYPE_COUNT 16

	// 8字节辅助偏移量
	#define ALIGN_OFFSET 3

	// 一次申请的内存大小
	#define ALLOC_MAX_SIZE 65536

	// 一次预分配的内存个数
	#define ONE_ALLOC_COUNT 32

	// 内存池
	class CMemoryPool
	{
	private:
		// 内存结点
		struct mem_node_t
		{
			union
			{
				mem_node_t* next;
				void* data;
			};
		};

		// 内存桶节点
		struct mem_chunk_t
		{
			mem_chunk_t* next;
			size_t size;
		};

		// 内存监控节点 监控内存使用情况
		struct mem_check_t
		{
		public:
			mem_check_t(void* p, size_t n, const char* name, int line):
				pMemory(p),nSize(n),nLine(line),fileName(name) {}
			mem_check_t(const mem_check_t& cpy) :
				pMemory(cpy.pMemory), nSize(cpy.nSize), nLine(cpy.nLine),
				fileName(cpy.fileName) {}
			void* pMemory;
			size_t nSize;
			int nLine;
			std::string fileName;
		};

		struct mem_check_t1
		{
			int useSize = 0;
			int allocCount = 0;
			int freeCount = 0;
		};

	public:
		CMemoryPool();
		virtual ~CMemoryPool();

	public:
		// 申请内存
		void* Alloc(size_t size);
		
		// 释放内存
		void Free(void* pData, size_t size);

		// 申请内存
		void* AllocDebug(size_t size, const char* fileName, int nLine);

		// 释放内存
		void FreeDebug(void* pData, size_t size);
	public:
		// 设置DEBUG 模式(开启
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值