栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++ 内存池

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ 内存池

C++ 内存池

参考链接:

1.https://blog.csdn.net/wangbuji/article/details/123393611

2.https://www.jianshu.com/p/bbba7e72fa59

内存碎片

  首先我们需要明确,内存碎片的目的到底是什么? 首先你要知道的是, 我们每次使用new T来初始化类型T的时候, 其实都发生以下两步操作:

  1. 内存分配,这一步使用的其实是operator new(也可以认为就是C语言中的malloc),这一步是直接和操作系统打交道的,操作系统需要经过相对繁琐的过程才能将一块指向空闲内存的指针返回给用户,所以这也是new比较耗时的一部分。

    malloc会用到brk和mmap这两个系统调用来获取内存。

    brk通过增加program break location(brk)地址来获取内存。

    mmap在memory mapping segment中创建一块内存返回给malloc。

  2. 构造函数初始化内存,既然内存分配耗时,那我们很容易想到的就是一次性分配一大块内存,然后在用户需要的时候再划分其中一部分给用户,这样的话,一次分配, 多次使用, 在特定的需求场景下是可以较大的提高效率的(比如libuv中频繁的申请和释放内存),而用来管理这所谓的一大块内存的数据结构, 也就是今天我们要说的内存池。

    另外一个好处在于, 频繁地使用new将导致系统内存空间碎片化,容易导致的后果就是很难找到一块连续的大块内存,造成内存碎片(非连续),空间利用率低。

  内存碎片分为内碎片和外碎片两部分。内碎片是指分配给作业的存储空间中未被利用的部分;外碎片是指系统中无法利用的小存储块。

(以下图片来源:https://blog.csdn.net/wangbuji/article/details/123393611)

TIPS:

目前操作系统普遍采用的段页式内存分配方式就是将进程的内存区域分为不同的段,然后将每一段由多个固定大小的页组成。通过页表机制,使段内的页可以不必连续处于同一内存区域,从而减少了外部碎片,然而同一页内仍然可能存在少量的内部碎片,只是一页的内存空间本就较小,从而使可能存在的内部碎片也较少。

(以下图片资源来源:百度百科。红色字体及线为博主所画)

基本思路

下面是一个简单的内存池思想的版本,实现的思想如下:

  1. 通过维护一个freeMemoryNodeList链表。当要申请空间的时候,就从链表上面摘下一个结点;要释放一个空间的时候,就从将释放的结点重新插入到链表里面。
  2. 每个结点的大小是提前通过template传入的,就是要分配的对象的大小。

SimpleMemoryPool.hpp

#pragma once

namespace U
{
	template
	class SimpleMemoryPool
	{
	private:
		struct MemoryNode
		{
			char data[ObjectSize];
			MemoryNode* pNext;
		};

		MemoryNode* freeMemoryNodeList;
		MemoryNode* pBack;//用于指向被释放动态申请的数组空间的初始位置,对于动态申请的数组空间,只能释放其初始位置

	private:
		MemoryNode* _InitMemoryNodeList()
		{
			MemoryNode* pNode = new MemoryNode[NumOfObjects];
			int count = 0;
			while (count < NumOfObjects - 1)
			{
				pNode[count].pNext = &pNode[count + 1];
				count++;
			}
			pNode[NumOfObjects - 1].pNext = nullptr;
			return pNode;
		}
	public:
		SimpleMemoryPool()
		{
			this->freeMemoryNodeList = _InitMemoryNodeList();
			pBack = this->freeMemoryNodeList;
		}

		~SimpleMemoryPool()
		{
			std::cout << "调用SimpleMemoryPool" << std::endl;

			if (this->pBack != nullptr)
				delete[] this->pBack;
		}


		void* Malloc()
		{
			if (nullptr == this->freeMemoryNodeList)
			{
				//重新分配一段内存空间
				std::cout << "重新添加内存空间" << std::endl;
				MemoryNode* pNode = _InitMemoryNodeList();
				//指向新的内容空间
				freeMemoryNodeList = pNode;
				pBack = pNode;
			}

			std::cout << "分配一个空间" << std::endl;
			MemoryNode* pRet = freeMemoryNodeList;
			freeMemoryNodeList = freeMemoryNodeList->pNext;
			pRet->pNext = nullptr;
			return pRet;
		}


		void Free(void* node)
		{
			std::cout << "释放一个空间" << std::endl;
			MemoryNode* pNode = (MemoryNode*)node;
			pNode->pNext = this->freeMemoryNodeList;//将需要释放的节点插入空闲节点头部
			this->freeMemoryNodeList = pNode;
		}

	};
}

main.cpp

class TestClass
{
private:
	static int count;
	int curIndex;

public:
	TestClass()
	{
		curIndex = count++;
	}

	~TestClass() {}

	void Print()
	{
		std::cout << this << ":";
		std::cout << "the " << curIndex << " object" << std::endl;
	}

	void* operator new(size_t size);
	void operator delete(void* p);

	void* operator new[](size_t size);
	void operator delete[](void* p, size_t size);
};

int TestClass::count = 0;

U::SimpleMemoryPool<4, 5> mp;

void* TestClass::operator new(size_t size)
{
	std::cout << "size:" << size << std::endl;
	return mp.Malloc();
}


void TestClass::operator delete(void* p)
{
	std::cout << "delete:" << p << std::endl;
	mp.Free(p);
}


void* TestClass::operator new[](size_t size)
{
	//size会比实际空间多4或8个字节,作用为记录数组长度以及内存对齐(至于具体是四个字节还是八个字节区别在于32位系统还是64位系统)
	std::cout << "size:" << size << std::endl;
	std::cout << "自定义的内存池不支持申请多个空间,所有默认调用系统malloc" << std::endl;
	return malloc(size);
}


void TestClass::operator delete[](void* p, size_t size)
{
	std::cout << "调用默认的free" << std::endl;
	std::cout << "delete [] size : " << size << std::endl;
	free(p);
}


int main(int argc, char* argv[])
{
	for (int i = 0; i < 3; i++)
	{
		TestClass* p = new TestClass;
		p->Print();
	}
	TestClass* p1 = nullptr;//3
	p1 = new TestClass;
	p1->Print();

	TestClass* p2 = new TestClass;
	p2->Print();

	//delete p1;

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

	//delete p3;

	TestClass* p4 = new TestClass[5];
	delete[]p4;

	system("pause");
	return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1033593.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号