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