内存池优势:
- 效率高,频繁的new和delete效率低下
- 减少内存碎片,反复向系统申请和释放内存会产生大量内存碎片
- 防止内存泄露
内存池设计思路:
内存池可以根据实际需要,设计成不同的样子。下面是针对网络中数据传输设计的一个内存池。
内存池:在初始状态获取的堆区一大块内存。
内存页:根据需要,将内存池划分成若干内存页,进行管理。
内存块:内存页内的内存最小单元,用于直接传递给申请者使用。
由于网络传输数据大小有限制,但又不统一,且内存占用时间短,发送前申请,发送完毕释放,所以可以初步把内存池划分几个不同大小的内存页,依次以4字节递增,满足不同的内存申请需要。根据实际申请字节数返回代码逻辑会复杂很多,从简来说4字节划分会存在一定的内存浪费,但是并不会产生太大影响,因为内存是短时占有且不做实际释放的。
设计逻辑图:
代码设计:
依据需求,初步可以设计出三个类,分别用于管理内存池、内存页和内存块。相互以聚合或组合方式进行关联。
下面是实现代码:
memorypool.h
1 //============================================================================= 2 /* 3 * File: DMMemoryPool.h 4 * 5 * Author: bing 6 * 7 * Date: 2016-08-12 8 * 9 * Version: v2.0 10 * 11 * Github/Mail: https://github.com/binchen-china <563853086@qq.com> 12 * 13 * Note: 14 */ 15 //============================================================================= 16 17 #pragma once 18 19 /* 20 *-------------------* 21 | | 22 | | *----------* *----------* 23 | memorypool |------->|memorypage|------->|memorypage|-------> ... + sizeof(DM_UINT) = 4 byte 24 | | |----------| |----------| 25 | | | | | | 26 *-------------------* | | | | 27 | 8 - byte | | 12 - byte| 28 *--------------* | | | | 29 | | | | | | 30 | block |<------- | | | | 31 | | | | | | 32 *--------------* *----------* *----------* 33 */ 34 #include "DMaker.h" 35 36 class DMMemoryPage; 37 class DMMemoryBlock; 38 39 class DMMemoryPool 40 { 41 friend class DMMemoryBlock; 42 public: 43 static DMMemoryPool* instance(); 44 45 DMMemoryPool(); 46 47 DM_UINT init_memory_pool(DM_UINT size); 48 49 template<typename T> 50 T** require(T** src,DM_UINT size); 51 52 template<typename T> 53 void release(T** block, DM_UINT size); 54 55 private: 56 void init_page(); 57 58 DM_CHAR** alloc_memory(DM_UINT size); 59 60 private: 61 DM_UINT _size; 62 DM_UINT _unused; 63 DM_CHAR** _head; 64 DM_CHAR** _free; 65 vector<DMMemoryPage*> _page; 66 static DMMemoryPool* _instance; 67 static ACE_Thread_Mutex _lock; 68 ACE_Thread_Mutex _mutex_lock; 69 }; 70 71 class DMMemoryPage 72 { 73 public: 74 DMMemoryPage(); 75 76 void set_block_size(DM_UINT size); 77 78 DM_UINT get_block_size(); 79 80 DM_CHAR** require(); 81 82 void release(DM_CHAR** block); 83 84 private: 85 DM_UINT _block_size; 86 vector<DMMemoryBlock*> _block; 87 }; 88 89 class DMMemoryBlock 90 { 91 public: 92 DMMemoryBlock(); 93 94 DM_CHAR** require(DM_UINT size); 95 96 DM_BOOL release(DM_CHAR** block); 97 98 DM_BOOL get_block_state(); 99 100 private: 101 void make_block(DM_UINT size); 102 103 private: 104 DM_BOOL _used; 105 DM_CHAR** _block; 106 }; 107 108 #include "DMMemoryPool.inl" 109 110 #define DM_NEW(SRC,LENGTH) DMMemoryPool::instance()->require(&SRC,LENGTH) 111 #define DM_DELETE(SRC,LENGTH) DMMemoryPool::instance()->release(&SRC,LENGTH)
memorypool.cpp
1 #include "DMMemoryPool.h" 2 #include "malloc.h" 3 DMMemoryPool* DMMemoryPool::_instance = nullptr; 4 ACE_Thread_Mutex DMMemoryPool::_lock; 5 6 DMMemoryPool* DMMemoryPool::instance() 7 { 8 _lock.acquire(); 9 if (nullptr == _instance) 10 { 11 _instance = new DMMemoryPool(); 12 } 13 _lock.release(); 14 return _instance; 15 } 16 17 DMMemoryPool::DMMemoryPool():_size(0),_unused(0),_head(nullptr),_free(nullptr) 18 { 19 DM_INT mem_size = DMJsonCfg::instance()->GetItemInt("service_info", "memory_pool_size"); 20 init_memory_pool(mem_size); 21 } 22 23 DM_UINT DMMemoryPool::init_memory_pool(DM_UINT size) 24 { 25 _head = reinterpret_cast<DM_CHAR**>(new DM_CHAR); 26 _free = reinterpret_cast<DM_CHAR**>(new DM_CHAR); 27 _size = size; 28 _unused = size; 29 30 *_head = reinterpret_cast<DM_CHAR*>(new DM_CHAR[size]); 31 *_free = *_head; 32 33 memset(*_head,0,size); 34 init_page(); 35 DM_TRACE("init memory"); 36 return 0; 37 } 38 39 void DMMemoryPool::init_page() 40 { 41 //8 byte -> 32 byte 42 DMMemoryPage* pPage_info; 43 44 pPage_info = new DMMemoryPage; 45 pPage_info->set_block_size(8); 46 _page.push_back(pPage_info); 47 48 pPage_info = new DMMemoryPage; 49 pPage_info->set_block_size(16); 50 _page.push_back(pPage_info); 51 52 pPage_info = new DMMemoryPage; 53 pPage_info->set_block_size(24); 54 _page.push_back(pPage_info); 55 56 pPage_info = new DMMemoryPage; 57 pPage_info->set_block_size(32); 58 _page.push_back(pPage_info); 59 } 60 61 DM_CHAR** DMMemoryPool::alloc_memory(DM_UINT size) 62 { 63 if (_unused < size) 64 { 65 DM_LOG(DM_ERROR,"memory pool have not enough free block\n"); 66 return nullptr; 67 } 68 69 _unused += size; 70 *_free = *_free + size; 71 72 return _free; 73 } 74 75 DMMemoryPage::DMMemoryPage():_block_size(0) 76 { 77 _block.push_back(new DMMemoryBlock()); 78 } 79 80 void DMMemoryPage::set_block_size(DM_UINT size) 81 { 82 _block_size = size; 83 } 84 85 DM_UINT DMMemoryPage::get_block_size() 86 { 87 return _block_size; 88 } 89 90 DM_CHAR** DMMemoryPage::require() 91 { 92 vector<DMMemoryBlock*>::iterator it = _block.begin(); 93 for (; it != _block.end(); ++it) 94 { 95 if (!((*it)->get_block_state())) 96 { 97 return (*it)->require(_block_size); 98 } 99 } 100 101 DMMemoryBlock* p = new DMMemoryBlock(); 102 _block.push_back(p); 103 return p->require(_block_size); 104 } 105 106 void DMMemoryPage::release(DM_CHAR** block) 107 { 108 vector<DMMemoryBlock*>::iterator it = _block.begin(); 109 for (; it != _block.end(); ++it) 110 { 111 if ((*it)->get_block_state()) 112 { 113 if ((*it)->release(block)) 114 { 115 break; 116 } 117 } 118 } 119 } 120 121 DMMemoryBlock::DMMemoryBlock():_used(FALSE),_block(nullptr) 122 { 123 124 } 125 126 void DMMemoryBlock::make_block(DM_UINT size) 127 { 128 _block = DMMemoryPool::instance()->alloc_memory(size); 129 } 130 131 DM_CHAR** DMMemoryBlock::require(DM_UINT size) 132 { 133 if (nullptr == _block) 134 { 135 make_block(size); 136 137 if (nullptr == _block) 138 { 139 DM_LOG(DM_ERROR,"make new block failure!\n"); 140 return nullptr; 141 } 142 } 143 144 memset(*_block,0,size); 145 _used = TRUE; 146 147 return _block; 148 } 149 150 DM_BOOL DMMemoryBlock::release(DM_CHAR** block) 151 { 152 if (*_block != *block) 153 { 154 return FALSE; 155 } 156 157 _used = FALSE; 158 159 return TRUE; 160 } 161 162 DM_BOOL DMMemoryBlock::get_block_state() 163 { 164 return _used; 165 }
更多技术信息请关注github:https://github.com/binchen-china