C/C++下内存管理是让几乎每一个程序员头疼的问题,分配足够的内存、追踪内存的分配、在不需要的时候释放内存——这个任务相当复杂。而直接使用系统调用malloc/free、new/delete进行内存分配和释放,有以下弊端:
- 调用malloc/new,系统需要根据“最先匹配”、“最优匹配”或其他算法在内存空闲块表中查找一块空闲内存,调用free/delete,系统可能需要合并空闲内存块,这些会产生额外开销
- 频繁使用时会产生大量内存碎片,从而降低程序运行效率
- 容易造成内存泄漏
内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。
本章先实现一个简单的内存池(CSingleMemoryPools)。该内存池提供一定数量、大小相等的内存块。该实例中,CSingleMemoryPools中的m_pMemoryFreeList负责对空闲内存块进行管理,每个内存块以_MemoryBlock类进行管理,其中首部有4个字节的指针块地址 + 4个字节的list表首地址 + 4位验证码,然后才是分配的内存。
1 #pragma once 2 3 //开发一个简单的内存池,用于内存管理。 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <list> 8 #include "ThreadLock.h" 9 10 #define MAX_MEMORYHEAD_SIZE 12 //4个字节的指针块地址 + 4个字节的List表首地址 + 4位验证码 11 #define MAGIC_CODE 0xFFFFFF //验证码 12 #define MEMORY_BUFFER_SIZE 1024 //该简单的内存池,提供1024字节大小的内存块 13 #define UINT32 unsigned int 14 15 struct _MemoryBlock //内存块的结构,12字节head+内存空间 16 { 17 void* m_pBrick; 18 _MemoryBlock() 19 { 20 m_pBrick = NULL; 21 }; 22 }; 23 24 25 class CSingleMemoryPools 26 { 27 public: 28 static CSingleMemoryPools& Instance() 29 { 30 if(m_pMemoryPools == NULL) 31 { 32 m_pMemoryPools = new CSingleMemoryPools(); 33 } 34 35 return *m_pMemoryPools; 36 } 37 38 public: 39 ~CSingleMemoryPools(void); 40 41 void* GetBuff(); 42 bool DelBuff(void* pBuff); 43 void DisplayMemoryList(); 44 45 private: 46 CSingleMemoryPools(void); 47 void Close(); 48 void* SetMemoryHead(void* pBuff, std::list<_MemoryBlock*>* pList, _MemoryBlock* pBlock); 49 void* GetMemoryHead(void* pBuff); 50 bool GetHeadMemoryBlock(void* pBuff, std::list<_MemoryBlock*>*& pList, _MemoryBlock*& pBlock); 51 52 private: 53 static CSingleMemoryPools* m_pMemoryPools; 54 std::list<_MemoryBlock*> m_pMemoryFreeList; //自由的内存块list 55 CThreadLock m_ThreadLock; 56 };
1 #include "SingleMemoryPools.h" 2 #include <iostream> 3 4 CSingleMemoryPools* CSingleMemoryPools::m_pMemoryPools = NULL; 5 CSingleMemoryPools::CSingleMemoryPools(void) 6 { 7 8 } 9 10 CSingleMemoryPools::~CSingleMemoryPools(void) 11 { 12 Close(); 13 } 14 15 16 void CSingleMemoryPools::Close() 17 { 18 //添加线程安全 19 CAutoLock autolock(&m_ThreadLock); 20 21 //删除所有已经归还的内存块, 22 //注:这个简单的内存池功能,关闭功能必须在所有分配出去的内存块都还回来之后才可以Close 23 24 std::list<_MemoryBlock*>::iterator itor = m_pMemoryFreeList.begin(); 25 while(itor != m_pMemoryFreeList.end()) 26 { 27 free((*itor)->m_pBrick); 28 m_pMemoryFreeList.erase(itor); 29 //兼容linux环境,linux下没有iterator erase( iterator _Where )方法, 有void erase( iterator _Where )方法 30 itor = m_pMemoryFreeList.begin(); 31 } 32 } 33 34 void* CSingleMemoryPools::SetMemoryHead(void* pBuff, std::list<_MemoryBlock*>* pList, _MemoryBlock* pBlock) 35 { 36 //组成内存包头 37 if(NULL == pBuff) 38 { 39 return NULL; 40 } 41 42 //因为一个long是4个字节,在linux和windows下都是一样的。所以加起来是12个 43 UINT32* plData = (UINT32*)pBuff; 44 45 plData[0] = (UINT32)pList; //内存List表首地址 46 plData[1] = (UINT32)pBlock; //所在链表的地址 47 plData[2] = (UINT32)MAGIC_CODE; //验证码 48 49 return &plData[3]; 50 } 51 52 void* CSingleMemoryPools::GetMemoryHead(void* pBuff) 53 { 54 if(NULL == pBuff) 55 { 56 return NULL; 57 } 58 59 long* plData = (long*)pBuff; 60 return &plData[3]; 61 } 62 63 bool CSingleMemoryPools::GetHeadMemoryBlock(void* pBuff, std::list<_MemoryBlock*>*& pList, _MemoryBlock*& pBlock) 64 { 65 char* szbuf = (char*)pBuff; 66 UINT32* plData = (UINT32*)(szbuf - MAX_MEMORYHEAD_SIZE); 67 if(plData[2] != (long)MAGIC_CODE) 68 { 69 return false; 70 } 71 else 72 { 73 pList = (std::list<_MemoryBlock*>*)plData[0]; //内存List表首地址 74 pBlock = (_MemoryBlock*)plData[1]; //所在链表的地址 75 76 return true; 77 } 78 79 } 80 81 void* CSingleMemoryPools::GetBuff() 82 { 83 //添加线程安全 84 CAutoLock autolock(&m_ThreadLock); 85 86 void* pBuff = NULL; 87 88 //判断是否有空闲的内存块。 89 if(m_pMemoryFreeList.empty()) 90 { 91 //申请内存块空间 92 pBuff = malloc(MEMORY_BUFFER_SIZE + MAX_MEMORYHEAD_SIZE); 93 memcpy(pBuff,0,MEMORY_BUFFER_SIZE + MAX_MEMORYHEAD_SIZE); 94 if(NULL == pBuff) 95 { 96 //printf_s("[CSingleMemoryPools::GetBuff] pBuff malloc = NULL.\n"); 97 return NULL; 98 } 99 100 //新建一个内存块单元 101 _MemoryBlock* pMemoryUsed = new _MemoryBlock(); 102 if(NULL == pMemoryUsed) 103 { 104 //printf_s("[CSingleMemoryPools::GetBuff] pMemoryBrick new = NULL.\n"); 105 delete pBuff; 106 return NULL; 107 } 108 109 pMemoryUsed->m_pBrick = pBuff; 110 return SetMemoryHead(pBuff, &m_pMemoryFreeList, pMemoryUsed); 111 } 112 113 //已有空余内存块,由于内存块头部已经初始化过了,这边无须再初始化,直接扔出来就可以了 114 _MemoryBlock* pBlockBuff = (m_pMemoryFreeList.front()); 115 m_pMemoryFreeList.pop_front(); 116 return GetMemoryHead(pBlockBuff->m_pBrick); 117 } 118 119 bool CSingleMemoryPools::DelBuff(void* pBuff) 120 { 121 //添加线程安全 122 CAutoLock autolock(&m_ThreadLock); 123 124 _MemoryBlock* pMemoryUsed = NULL; 125 std::list<_MemoryBlock*>* pCurrMemoryList = NULL; 126 127 if(false == GetHeadMemoryBlock(pBuff, pCurrMemoryList, pMemoryUsed)) 128 { 129 return false; 130 } 131 132 if(NULL != pMemoryUsed && pCurrMemoryList == &m_pMemoryFreeList ) 133 { 134 m_pMemoryFreeList.push_back(pMemoryUsed); 135 return true; 136 } 137 138 //printf_s("[CSingleMemoryPools::DelBuff] pBuff = 0x%08x is not memoryPool.\n", pBuff); 139 return false; 140 } 141 142 void CSingleMemoryPools::DisplayMemoryList() 143 { 144 int nFreeCount = m_pMemoryFreeList.size(); 145 printf_s("[CSingleMemoryPools::DisplayMemoryList] pMemoryFree nFreeCount = %d, Size = %d.\n", nFreeCount, MEMORY_BUFFER_SIZE * nFreeCount); 146 } 147 148 // TODO: 在 STDAFX.H 中 149 // 引用任何所需的附加头文件,而不是在此文件中引用 150 //#include "MemoryPools.h" 151 152 //重载New和Delete操作符 153 inline void* operator new(size_t szBuff) 154 { 155 //注:由于这是一个简单的内存池,大小固定,所以参数szBuff没有用起来,后期会开发一个多层级大小的内存池 156 void* pBuff = CSingleMemoryPools::Instance().GetBuff(); 157 //OUR_DEBUG((LM_ERROR, "[New] Size = %d Address = [0x%08x].!\n", (int)szBuff, pBuff)); 158 return pBuff; 159 } 160 161 inline void operator delete(void* p) 162 { 163 if(false == CSingleMemoryPools::Instance().DelBuff(p)) 164 { 165 // OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] false!\n", p)); 166 //CSingleMemoryPools::Instance().DisplayMemoryList(p); 167 } 168 else 169 { 170 //OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] OK!\n", p)); 171 } 172 } 173 174 inline void operator delete[]( void * p ) 175 { 176 if(false == CSingleMemoryPools::Instance().DelBuff(p)) 177 { 178 // OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] false!\n", p)); 179 //CSingleMemoryPools::Instance().DisplayMemoryList(p); 180 } 181 else 182 { 183 //OUR_DEBUG((LM_ERROR, "[Delete]*p = [0x%08x] OK!\n", p)); 184 } 185 }
使用一个list来管理内存,相对于用两个list(一个FreeList ,一个 Used List)的优点:更加简洁,管理更加简单;缺陷:无法知晓已经分配出去的内存块。
来源:https://www.cnblogs.com/pilipalajun/p/5418286.html