当前位置:   article > 正文

内存池的实现_内存池实现

内存池实现

一、内存

1、内存池的概念

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

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

2、内存池的流程和设计

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

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

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

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

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

3、内存池的结构示意图

4、code

  1. #include<iostream>
  2. using namespace std;
  3. template<int ObjectSize,int NumofObjects = 20>
  4. /*ObjectSize:内存块中每个节点的大小
  5. NumofObject:每个内存块的节点的个数
  6. */
  7. class MemPoll
  8. {
  9. private:
  10. struct FreeNode//节点
  11. {
  12. FreeNode* next;
  13. char data[ObjectSize];//这个节点的大小,即使用这块内存的大小
  14. };
  15. struct MemBlock//内存块
  16. {
  17. MemBlock* next;
  18. FreeNode data[NumofObjects];//默认每个内存快有20个节点
  19. };
  20. FreeNode* nodeheader;//指向当前待分配的空闲节点
  21. MemBlock* memblockheader;//指向当前最新的内存块
  22. public:
  23. MemPoll()
  24. {
  25. nodeheader = nullptr;
  26. memblockheader = nullptr;
  27. }
  28. ~MemPoll()//依次去释放内存块
  29. {
  30. MemBlock* cur;
  31. while (memblockheader)
  32. {
  33. cur = memblockheader->next;
  34. delete memblockheader;
  35. memblockheader = cur;
  36. }
  37. }
  38. void* malloc();
  39. void free(void*);
  40. };
  41. template<int ObjectSize,int NumofObjects>
  42. void* MemPoll<ObjectSize, NumofObjects>::malloc()//开辟内存时
  43. {
  44. if (nodeheader == nullptr)//如果此时无空闲节点
  45. {
  46. MemBlock* newBlock = new MemBlock;//开辟一个内存块
  47. newBlock->next = nullptr;
  48. nodeheader = &newBlock->data[0];//新开辟内存块的第一个空闲节点
  49. for (int i = 1; i < NumofObjects; ++i)
  50. {
  51. newBlock->data[i - 1].next = &newBlock->data[i];
  52. }
  53. newBlock->data[NumofObjects - 1].next = nullptr;//将内存块中的这些节点连接起来
  54. if (memblockheader == nullptr)//说明此时为首次申请内存块
  55. {
  56. memblockheader = newBlock;
  57. }
  58. else//否则将之前的内存块和新开辟的内存块连接起来
  59. {
  60. newBlock->next = memblockheader;
  61. memblockheader = newBlock;
  62. }
  63. }
  64. void* cur = nodeheader;
  65. nodeheader = nodeheader->next;
  66. return cur;//返回一个空闲的节点
  67. }
  68. template<int ObjectSize, int NumofObjects>
  69. void MemPoll<ObjectSize, NumofObjects>::free(void* p)
  70. {
  71. //将这个不被使用的节点归还给内存块
  72. FreeNode* cur = (FreeNode*)p;
  73. cur->next = nodeheader;
  74. nodeheader = cur;
  75. }
  76. class ActualClass
  77. {
  78. private:
  79. static int count;
  80. int No;
  81. public:
  82. ActualClass()
  83. {
  84. No = count;
  85. count++;
  86. }
  87. void Print()
  88. {
  89. cout << this << ":" << "the" << No << "th object" << endl;
  90. }
  91. void* operator new(size_t size);
  92. void operator delete(void* p);
  93. };
  94. int ActualClass::count = 0;
  95. MemPoll<sizeof(ActualClass), 2> mp;
  96. void* ActualClass::operator new(size_t size)
  97. {
  98. return mp.malloc();
  99. }
  100. void ActualClass::operator delete(void* p)
  101. {
  102. mp.free(p);
  103. }
  104. int main()
  105. {
  106. ActualClass* p1 = new ActualClass;
  107. p1->Print();
  108. ActualClass* p2 = new ActualClass;
  109. p2->Print();
  110. delete p1;
  111. p1 = new ActualClass;
  112. p1->Print();
  113. ActualClass* p3 = new ActualClass;
  114. p3->Print();
  115. delete p1;
  116. delete p2;
  117. delete p3;
  118. system("pause");
  119. return 0;
  120. }

4、内存池的特点

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

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

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

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

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

更方便于管理内存。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/292428
推荐阅读
相关标签
  

闽ICP备14008679号