赞
踩
内存池(Memory Pool)是一种内存分配方式。通常我们习惯直接使用new、malloc等API申请内存,这样做的缺点在于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。
内存池则是在真正使用内存之前,预先申请分配一定数量、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。
1. 先申请一块连续的内存空间,该段内存空间能够容纳一定数量的对象。
2. 每个对象连同一个指向下一个对象的指针一起构成一个内存节点(Memory Node)。各个空闲的内存节点通过指针形成一个链表,链表的每一个内存节点都是一块可供分配的内存空间。
3. 某个内存节点一旦分配出去,从空闲内存节点链表中去除。
4. 一旦释放了某个内存节点的空间,又将该节点重新加入空闲内存节点链表。
5. 如果一个内存块的所有内存节点分配完毕,若程序继续申请新的对象空间,则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。
- #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;
- }
针对特殊情况,例如需要频繁分配释放固定大小的内存对象时,不需要复杂的分配算法和多线程保护。也不需要维护内存空闲表的额外开销,从而获得较高的性能。
由于开辟一定数量的连续内存空间作为内存池块,因而一定程度上提高了程序局部性,提升了程序性能。
比较容易控制页边界对齐和内存字节对齐,没有内存碎片的问题。
当需要分配管理的内存在100M一下的时候,采用内存池会节省大量的时间,否则会耗费更多的时间。
内存池可以防止更多的内存碎片的产生。
更方便于管理内存。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。