内存池的实现

一、内存池

1、内存池的概念

        内存池(Memory Pool)是一种内存分配方式。通常我们习惯直接使用new、malloc等API申请内存,这样做的缺点在于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。

  内存池则是在真正使用内存之前,预先申请分配一定数量、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。

2、内存池的流程和设计

1. 先申请一块连续的内存空间,该段内存空间能够容纳一定数量的对象。

2. 每个对象连同一个指向下一个对象的指针一起构成一个内存节点(Memory Node)。各个空闲的内存节点通过指针形成一个链表,链表的每一个内存节点都是一块可供分配的内存空间。

3. 某个内存节点一旦分配出去,从空闲内存节点链表中去除。

4. 一旦释放了某个内存节点的空间,又将该节点重新加入空闲内存节点链表。

5. 如果一个内存块的所有内存节点分配完毕,若程序继续申请新的对象空间,则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。

3、内存池的结构示意图

4、code

#include<iostream>

using namespace std;

template<int ObjectSize,int NumofObjects = 20>
/*ObjectSize:内存块中每个节点的大小
NumofObject:每个内存块的节点的个数
*/
class MemPoll
{
private:
	struct FreeNode//节点
	{
		FreeNode* next;
		char data[ObjectSize];//这个节点的大小,即使用这块内存的大小
	};

	struct MemBlock//内存块
	{
		MemBlock* next;
		FreeNode data[NumofObjects];//默认每个内存快有20个节点
	};

	FreeNode* nodeheader;//指向当前待分配的空闲节点
	MemBlock* memblockheader;//指向当前最新的内存块

public:
	MemPoll()
	{
		nodeheader = nullptr;
		memblockheader = nullptr;
	}
	~MemPoll()//依次去释放内存块
	{
		MemBlock* cur;
		while (memblockheader)
		{
			cur = memblockheader->next;
			delete memblockheader;
			memblockheader = cur;
		}
	}
	void* malloc();
	void free(void*);
};

template<int ObjectSize,int NumofObjects>
void* MemPoll<ObjectSize, NumofObjects>::malloc()//开辟内存时
{
	if (nodeheader == nullptr)//如果此时无空闲节点
	{
		MemBlock* newBlock = new MemBlock;//开辟一个内存块
		newBlock->next = nullptr;
		nodeheader = &newBlock->data[0];//新开辟内存块的第一个空闲节点
		for (int i = 1; i < NumofObjects; ++i)
		{
			newBlock->data[i - 1].next = &newBlock->data[i];
		}
		newBlock->data[NumofObjects - 1].next = nullptr;//将内存块中的这些节点连接起来

		if (memblockheader == nullptr)//说明此时为首次申请内存块
		{
			memblockheader = newBlock;
		}
		else//否则将之前的内存块和新开辟的内存块连接起来
		{
			newBlock->next = memblockheader;
			memblockheader = newBlock;
		}
	}
	void* cur = nodeheader;
	nodeheader = nodeheader->next;
	return cur;//返回一个空闲的节点
}

template<int ObjectSize, int NumofObjects>
void MemPoll<ObjectSize, NumofObjects>::free(void* p)
{
	//将这个不被使用的节点归还给内存块
	FreeNode* cur = (FreeNode*)p;
	cur->next = nodeheader;
	nodeheader = cur;
}

class ActualClass
{
private:
	static int count;
	int No;
public:
	ActualClass()
	{
		No = count;
		count++;
	}

	void Print()
	{
		cout << this << ":" << "the" << No << "th object" << endl;
	}

	void* operator new(size_t size);
	void operator delete(void* p);
};
int ActualClass::count = 0;
MemPoll<sizeof(ActualClass), 2> mp;

void* ActualClass::operator new(size_t size)
{
	return mp.malloc();
}

void ActualClass::operator delete(void* p)
{
	mp.free(p);
}

int main()
{
	ActualClass* p1 = new ActualClass;
	p1->Print();

	ActualClass* p2 = new ActualClass;
	p2->Print();
	delete p1;

	p1 = new ActualClass;
	p1->Print();

	ActualClass* p3 = new ActualClass;
	p3->Print();

	delete p1;
	delete p2;
	delete p3;
	system("pause");
	return 0;
}

4、内存池的特点

针对特殊情况,例如需要频繁分配释放固定大小的内存对象时,不需要复杂的分配算法和多线程保护。也不需要维护内存空闲表的额外开销,从而获得较高的性能。

由于开辟一定数量的连续内存空间作为内存池块,因而一定程度上提高了程序局部性,提升了程序性能。

比较容易控制页边界对齐和内存字节对齐,没有内存碎片的问题。

当需要分配管理的内存在100M一下的时候,采用内存池会节省大量的时间,否则会耗费更多的时间。

内存池可以防止更多的内存碎片的产生。

更方便于管理内存。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存池是一种常见的内存管理技术,它可以在程序启动时预先分配一定数量的内存空间,并将其划分为多个固定大小的块,然后在程序运行过程中动态地将这些块分配给需要使用内存的对象,从而减少内存碎片和内存分配的时间开销。下面是一个简单的内存池实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define BLOCK_SIZE 1024 #define BLOCK_NUM 10 typedef struct _memory_block { void *start; void *end; struct _memory_block *next; } memory_block; typedef struct _memory_pool { size_t block_size; memory_block *free_list; memory_block *used_list; } memory_pool; memory_pool *memory_pool_create(size_t block_size) { memory_pool *pool = (memory_pool *) malloc(sizeof(memory_pool)); pool->block_size = block_size; pool->free_list = NULL; pool->used_list = NULL; for (int i = 0; i < BLOCK_NUM; i++) { memory_block *block = (memory_block *) malloc(sizeof(memory_block)); block->start = malloc(block_size); block->end = (char *) block->start + block_size; block->next = pool->free_list; pool->free_list = block; } return pool; } void *memory_pool_alloc(memory_pool *pool, size_t size) { memory_block *block = pool->free_list; while (block) { if ((char *) block->end - (char *) block->start >= size) { void *ptr = block->start; block->start = (char *) block->start + size; if (block->start == block->end) { pool->free_list = block->next; block->next = pool->used_list; pool->used_list = block; } return ptr; } block = block->next; } return NULL; } void memory_pool_free(memory_pool *pool) { memory_block *block = pool->used_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } block = pool->free_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } free(pool); } int main() { memory_pool *pool = memory_pool_create(BLOCK_SIZE); char *str1 = (char *) memory_pool_alloc(pool, 10); char *str2 = (char *) memory_pool_alloc(pool, 20); char *str3 = (char *) memory_pool_alloc(pool, 30); strcpy(str1, "hello"); strcpy(str2, "world"); strcpy(str3, "memory pool"); printf("%s %s %s\n", str1, str2, str3); memory_pool_free(pool); return 0; } ``` 该示例中,首先定义了两个结构体:memory_block表示内存块,包括起始地址、结束地址和下一个内存块的指针;memory_pool表示内存池,包括块大小、空闲链表和已用链表。 然后,定义了三个函数:memory_pool_create用于创建内存池,先分配一定数量的内存块,并将其加入空闲链表;memory_pool_alloc用于从内存池中分配一块指定大小的内存空间,遍历空闲链表,找到第一个大小足够的内存块,并将其划分为新的内存空间;memory_pool_free用于释放内存池中的所有内存块,将已用链表和空闲链表中的内存块全部释放。 最后,在main函数中创建一个内存池,并使用memory_pool_alloc从内存池中分配三个字符串空间,将其赋值并打印出来,最后使用memory_pool_free释放内存池中的所有内存块。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值