C++内存管理 --- 内存池

引子
  • new实际分配的内存:
    在这里插入图片描述
  • 从new实际分配的内存可以看出,除了我们实际需要的内存之外,系统分配了很多增加的内容,例如开头和结尾的两个cookie,各8byte。这两个cookie记录了实际分配空间的大小,同时在delete的时候告诉系统实际需要释放的空间。
  • 为了减少大量小空间被分配时,过多cookie造成的内存浪费,我们引入了内存池。内存池的思想是一次性申请一大块空间,每次使用时返回一小块,这样做的优点在于:既减少了申请内存操作的次数,提升了程序运行的效率;又减少了cookie带来的内存浪费。
  • 通常内存池内部是一个单向链表将内存片串联起来,便于管理;
    在这里插入图片描述
一、单独类内存池
class A
{
public:
	A(int x) :i(x) {};
	int get() { return i; }

	void* operator new(size_t);
	void operator delete(void*, size_t);

private:
	A* next;
	static A* freeStore;     //指向可用首地址
	static const int Achunk; //内存池可容纳的对象个数

private:
	int i;
};

A* A::freeStore = 0;
const int A::Achunk = 24;

void* A::operator new(size_t size)
{
	A* p;
	if (!freeStore)
	{
	//linked list is empty
		size_t chunk = Achunk * size;
		freeStore = p = reinterpret_cast<A*>(new char[chunk]);
		//将一大快分片
		for (; p != &freeStore[Achunk - 1]; ++p)
		{
			p->next = p + 1;
		}
		p->next = 0;
	}
	p = freeStore;
	freeStore = freeStore->next;
	return p;
}

void A::operator delete(void* p, size_t)
{
	// 将delete object插回free list前端
	(static_cast<A*>(p))->next = freeStore;
	freeStore = static_cast<A*>(p);
}
  • 内存池的优势在于提高运行速度,减少内存浪费;
  • 这样处理存在的问题时是:是否有必要为了消除cookie而额外引入一个4byte的指针,对于上例来说,膨胀率等于100%,以下例子巧妙解决了这个问题;
二、改进版单独类内存池
class A
{
private:
	struct ARep
	{
		int i;
		char type;
	};
private:
	union 
	{
		ARep rep;
		A* next;
	};

public:
	A(int x) :i(x) {};
	int get() { return i; }

	void* operator new(size_t);
	void operator delete(void*, size_t);

private:
	static A* freeStore;      //指向可用内存首地址
	static const int Achunk;  //内存池可容纳的对象个数

private:
	int i;
};

A* A::freeStore = 0;
const int A::Achunk = 24;

void* A::operator new(size_t size)
{
	if (size != sizeof(A))
		return ::operator new(size);
	A* p = freeStore;
	if (p)
		freeStore = p->next;
	else
	{
		//linked list is empty
		size_t chunk = Achunk * size;
		A* newBlock = static_cast<A*>(::operator new(Achunk * sizeof(A)));
		//将一大快分片,并串联
		for (int i = 1; i < Achunk; ++i)
		{
			newBlock[i].next = &newBlock[i + 1];
		}
		newBlock[Achunk - 1].next = 0; //结束list
		p = newBlock;
		freeStore = &newBlock[1];
	}
	return p;
}

void A::operator delete(void* p, size_t)
{
	// 将delete object插回free list前端
	(static_cast<A*>(p))->next = freeStore;
	freeStore = static_cast<A*>(p);
}
  • 使用嵌入式指针后,我们借用A对象所占空间的前4字节,用于连接空闲内存块(储存指针),一旦这一块被分配出去,这4个字节不再需要;可以说嵌入式指针和成员变量是在不同时期使用了同一块内存
  • 这两种内存池的实现方式类似,都是为单独的类进行内存管理,这失去了重用性,我们如何解决这一问题呢?
三、静态分配器
class m_allocator
{
private:
	struct obj
	{
		struct obj* next; //embedded pointer
	};
public:
	void* allocate(size_t);
	void deallocate(void*, size_t);
private:
	obj* freeStore = nullptr;
	const int CHUNK = 5;
};

void* m_allocator::allocate(size_t size)
{
	obj* p;
	if (!freeStore)
	{
		size_t chunk = CHUNK * size;
		freeStore = p = (obj*)malloc(chunk);
		for (int i = 0; i < CHUNK - 1; ++i)
		{
			p->next = (obj*)((char*)p + size);
			p = p->next;
		}
		p->next = nullptr;
	}
	p = freeStore;
	freeStore = freeStore->next;
	return p;

	
}

void m_allocator::deallocate(void* p, size_t)
{
	((obj*)p)->next = freeStore;
	freeStore = (obj*)p;
}

在这里插入图片描述

  • 这样一来,app classes 不再与内存分配的细节纠葛,而全权交给allocator去管理;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
急速内存池是一种高效利用内存的数据结构,可以有效提高程序的运行效率。在实现急速内存池的过程中,可以结合CPU Cache来进一步优化操作。 CPU Cache是一种高速缓存,与主内存之间的数据传输速度差异较大,读写CPU Cache较快。因此,将急速内存池的数据存储在CPU Cache中可以大大缩短访问时间,提高效率。 首先,我们可以通过调整急速内存池的数据结构,使其更加适合CPU Cache的使用。可以使用连续的内存空间来存储数据,这样可以减少因为内存碎片导致的缓存未命中的情况。另外,可以使用线程私有的内存池,避免多线程之间的竞争,提高数据访问效率。 其次,可以利用CPU Cache的特性,使用合适的数据结构组织内存池的数据。例如,可以使用哈希表来快速查找和存储数据,以减少因为内存池数据过大导致的访问时间增加。同时,可以使用LRU(最近最少使用)算法来管理内存池中的数据,保证经常访问的数据处于高速缓存中。 最后,可以通过预取数据的方式利用CPU Cache。例如,在遍历内存池的过程中,可以预先将下一段要访问的数据加载到缓存中,避免缓存未命中带来的延迟。可以通过提前设置预取指令或者使用特定的编译器优化方式实现预取操作。 总之,结合CPU Cache实现急速内存池可以利用缓存的高速读写性能,提高程序的运行效率。通过调整内存池的数据结构、使用合适的数据结构和算法、以及预取数据等方式,可以充分利用CPU Cache的特点,并减少对主内存的访问,从而提高程序的性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值