整个内存池代码就一百多行, 代码内容也非常简单, windows环境下, 消耗大约为malloc/free
的1/15左右(未做严谨测试, 数据仅供参考)
项目github地址
为什么需要使用内存池
功能需求
- 功能足够简单, 尽可能不使用第三方库
- 每次申请的内存都是固定大小, 随用随删
- 多线程环境下为每个线程绑定一个内存池, 避免使用锁
设计思路
- 提前申请一大块内存, 划分为N份, bitset记录每一份内存有没有被使用
- 移动offset检查可用的内存块, 循环重复这个过程
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| #include <vector> using uint64 = unsigned long long; #define bit_size 64
class bit { public: bit(size_t len) { this->_len = len; this->_bitset.resize(len / bit_size, 0); if (len % bit_size != 0) { this->_bitset.push_back(0); } } bit(const bit&) = delete; bit& operator=(const bit&) = delete; bool get(size_t offset) { assert(offset < this->_len); uint64 index = offset / bit_size; uint64 mod = offset % bit_size; uint64 mask = (uint64)1 << mod; uint64 result = this->_bitset[index] & mask; return result != 0; } void set(size_t offset, bool value) { assert(offset < this->_len); uint64 index = offset / bit_size; uint64 mod = offset % bit_size; if (!value) { uint64 mask = ~(1 << mod); this->_bitset[index] = this->_bitset[index] & mask; } else { uint64 mask = (uint64)1 << mod; this->_bitset[index] = this->_bitset[index] | mask; } } private: std::vector<uint64> _bitset; size_t _len; }; #define failed_skip 3 class memory_wheel { public: memory_wheel(size_t class_sizeof, size_t chunk_size) { this->_chunk_size = chunk_size; this->_class_sizeof = class_sizeof; this->_offset = 0; this->_failed = 0; this->_using = new bit(chunk_size); this->_buffer = malloc(chunk_size * class_sizeof); this->_start = (uintptr_t)this->_buffer; this->_over = this->_start + chunk_size * class_sizeof; }
~memory_wheel() { free(this->_buffer); delete this->_using; this->_offset = 0; this->_buffer = nullptr; this->_failed = 0; }
memory_wheel(const memory_wheel&) = delete; memory_wheel& operator=(const memory_wheel&) = delete;
void* palloc() { if (this->_offset >= this->_chunk_size) { this->_offset = 0; } if (!this->_using->get(this->_offset)) { this->_using->set(this->_offset, 1); uintptr_t addr = (uintptr_t)this->_buffer; void* p = (void*)(addr + this->_class_sizeof * this->_offset++); memset(p, 0, this->_class_sizeof); return p; } if (this->_failed++ >= failed_skip) { ++this->_offset; this->_failed = 0; } void* p = malloc(this->_class_sizeof); if (!p) return nullptr; memset(p, 0, this->_class_sizeof); return p; }
void recycle(void* p) { if (!p) return; uintptr_t addr = (uintptr_t)p; if (addr >= this->_start && addr <= (this->_over - this->_class_sizeof)) { auto diff = addr - this->_start; auto mod = diff % this->_class_sizeof; assert(mod == 0); size_t offset = diff / this->_class_sizeof; this->_using->set(offset, 0); } else { free(p); } } private: size_t _class_sizeof; size_t _chunk_size; size_t _offset; void* _buffer; int _failed; uintptr_t _start; uintptr_t _over; bit* _using; };
|
Usage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class TestClass { public: TestClass(int v1, int v2) { this->v1 = v1; this->v2 = v2; this->v3 = 0; this->b = false; } TestClass(int v1, int v2, unsigned long long v3) { this->v1 = v1; this->v2 = v2; this->v3 = v3; this->b = false; } bool b; int v1; int v2; unsigned long long v3; }; #define PLACEMENT_NEW(ptr, _type, ...) new(ptr) _type { __VA_ARGS__ } #define NEW(pool, _type, ...) PLACEMENT_NEW((pool)->palloc(), _type, __VA_ARGS__) int main(int argc, char* argv[]) { memory_wheel wheel(sizeof(TestClass), 512); TestClass* obj1 = NEW(&wheel, TestClass, 1, 2); wheel.recycle(obj1); TestClass* obj2 = NEW(&wheel, TestClass, 50, 200, 999); wheel.recycle(obj2); }
|