内存池设计与实现

内存池设计与实现

alloctor.h

#ifndef _ALLOCTOR_H_
#define _ALLOCTOR_H_

void* operator new(size_t size);
void operator delete(void* p);

void* operator new[](size_t size);
void operator delete[](void* p);

void* mem_alloc(size_t size);
void  mem_free(void* p);

#endif  // !_ALLOCTOR_H_

alloctor.cpp

#include "alloctor.h"
#include "memory_manage.h"

void* operator new(size_t size){
	return MemoryManage::get_instance().mm_alloc_memory(size);
}

void operator delete(void* p) {
	MemoryManage::get_instance().mm_free_memory(p);
}

void* operator new[](size_t size) {
	return MemoryManage::get_instance().mm_alloc_memory(size);
}

void operator delete[](void* p) {
	MemoryManage::get_instance().mm_free_memory(p);
}

void* mem_alloc(size_t size) {
	return MemoryManage::get_instance().mm_alloc_memory(size);
}

void  mem_free(void* p) {
	MemoryManage::get_instance().mm_free_memory(p);
}

memory_pool.h

#ifndef _MEMORY_MANAGE_H_
#define _MEMORY_MANAGE_H_

#include <stdlib.h>
#include <mutex>

/*
#ifdef _DEBUG
	#include <stdio.h>
	#include <assert.h>
	#define xPrintf(...) printf(__VA_ARGS__)
#else
	#define	xPrintf(...)
#endif // _DEBUG
*/

const int MAX_MEMORY_SIZE = 128;
 
class MemoryAlloc;
// 描述单个内存块的信息  x64 : 32字节
class MemoryBlock {
public:
	MemoryAlloc* _alloc;    // 所属的内存池
	MemoryBlock* _next;     // 下一块位置
	int _nId;               // 内存块编号
	int _nRef;              // 引用次数
	bool _inpool;           // 释放在内存池中
private:
	//下面三个是为了内存对齐
	char c1;
	char c2;
	char c3;
};

// 内存池
class MemoryAlloc {
public:
	MemoryAlloc() : 
		_cell_header(nullptr),
		_memory_pool_addr(nullptr), 
		_block_size(0), 
		_block_num(0) {}
	~MemoryAlloc() {
		if (_memory_pool_addr) {
			free(_memory_pool_addr); 
		}
	}

public:
	// 初始化
	void init_memory_pool();
	// 申请内存
	void* ma_alloc_memory(size_t size);
	// 释放内存
	void ma_free_memory(void* memory);
	
protected:
	MemoryBlock*    _cell_header;         // 内存池第一个内存块
	char*           _memory_pool_addr;    // 内存池起始地址
	size_t          _block_size;          // 内存单元大小
	size_t          _block_num;           // 内存单元数量
	std::mutex      _mutex;               // 锁

};

// 便于在声明类成员变量时初始化MemoryAlloc的成员数据
template<size_t block_size, size_t block_num>
class MemoryAlloctor : public MemoryAlloc {
public:
	MemoryAlloctor() {
		// xPrintf("MemoryAlloctor\n");
		// 为了防止传入的nSize不是整数倍,这样的话会造成内存碎片,因此我们使用运算,如果传入的数值不是整数倍,那么就转换为整数倍
		const size_t n = sizeof(void*);
		_block_size = (block_size / n) * n + (block_size % n ? n : 0);
		_block_num = block_num;
	}
};

// 内存管理工具
class MemoryManage {
private:
	MemoryManage() {
		init_memory_array(0, 64, &_memory_size_64);
		init_memory_array(65, 128, &_memory_size_128);
		/*init_memory_array(129, 256, &_memory_size_256);
		init_memory_array(257, 512, &_memory_size_512);
		init_memory_array(513, 1024, &_memory_size_1024);*/
		// xPrintf("MemoryManage\n");
	}
	~MemoryManage() {}

public:
	// 返回内存管理的引用
	static MemoryManage& get_instance();
	// 申请内存
	void* mm_alloc_memory(size_t size);
	// 释放内存
	void mm_free_memory(void* memory);
	// 增加内存块的引用计数
	void add_ref(void* memory);

private:
	// 初始化内存池映射数组
	void init_memory_array(int nbegin, int nend, MemoryAlloc* memory);

private:
	MemoryAlloctor<64, 4000000> _memory_size_64;        //内存池,该内存池有100块单个内存块,每个内存块64KB(下同)
	MemoryAlloctor<128, 2000000> _memory_size_128;
	/*MemoryAlloctor<256, 100000> _memory_size_256;
	MemoryAlloctor<512, 100000> _memory_size_512;
	MemoryAlloctor<1024, 100000> _memory_size_1024;*/
	
	MemoryAlloc* _memory_array[MAX_MEMORY_SIZE + 1];    //数组用来存储上面的那些内存池
};

#endif  // !_MEMORY_MANAGE_H_

memory_pool.cpp

#include "memory_manage.h"

// 初始化
void MemoryAlloc::init_memory_pool() {
	// 断言
	// assert(_memory_pool_addr == nullptr);
	// 如果不为空,说明已经初始化过了,直接return
	if (_memory_pool_addr) { return; }
	// 计算单个内存块的大小
	size_t single_cell_size = _block_size + sizeof(MemoryBlock);
	// 计算内存池总大小
	size_t total_pool_size = single_cell_size * _block_num;
	// 向系统申请池的内存
	_memory_pool_addr = (char*)malloc(total_pool_size);

	// 初始化内存池
	// 初始化第一块内存
	_cell_header = (MemoryBlock*)_memory_pool_addr;
	_cell_header->_inpool = true;
	_cell_header->_nId = 0;
	_cell_header->_nRef = 0;
	_cell_header->_alloc = this;
	_cell_header->_next = nullptr;
	// 初始化剩余块的内容
	MemoryBlock* temp_next = _cell_header;
	for (size_t n = 1; n < _block_num; ++n) {
		MemoryBlock* temp = (MemoryBlock*)(_memory_pool_addr + (n * single_cell_size));
		temp->_inpool = true;
		temp->_nId = n;
		temp->_nRef = 0;
		temp->_alloc = this;
		temp->_next = nullptr;
		temp_next->_next = temp;
		temp_next = temp;
	}
}

// 申请内存
void* MemoryAlloc::ma_alloc_memory(size_t size) {
	//加锁
	std::lock_guard<std::mutex> lock(_mutex);
	// 如果内存池未初始化,那么进行初始化
	if (!_memory_pool_addr) { init_memory_pool(); }

	MemoryBlock* memory_retrun = nullptr;
	/*如果内存池使用完了,那么_pHeader应该指向某个内存块的最后nullptr尾指针
    此时调用malloc向系统申请内存,不向我们的内存池进行内存申请*/
	if (nullptr == _cell_header) {
		memory_retrun = (MemoryBlock*)malloc(_block_size + sizeof(MemoryBlock));
		memory_retrun->_inpool = false;
		memory_retrun->_nId = -1;
		memory_retrun->_nRef = 1;
		// 这个不属于内存处管理,所以设置为nullptr
		memory_retrun->_alloc = nullptr; 
		memory_retrun->_next = nullptr;
		printf("ma_alloc_memory: %llx, id=%d, size=%d\n", memory_retrun, memory_retrun->_nId, size);
	} else {
		//申请的时候将_pHeader向后移动
		memory_retrun = _cell_header;
		_cell_header = _cell_header->_next;
		// assert(0 == memory_retrun->_nRef);
		memory_retrun->_nRef = 1;
	}
	// xPrintf("ma_alloc_memory: %llx, id=%d, size=%d\n", memory_retrun, memory_retrun->_nId, size);
	return (char*)memory_retrun + sizeof(MemoryBlock);
}

// 释放内存
void MemoryAlloc::ma_free_memory(void* memory) {
	// 参数传入的是实际可用的内存地址,需要减去sizeof(MemoryBlock)才能得到整个单个内存块的内容
	MemoryBlock* memory_block = (MemoryBlock*)((char*)memory - sizeof(MemoryBlock));
	// assert(1 == memory_block->_nRef);
	
	// 如果申请的内存属于内存池中的,不是系统申请的,则执行if
	if (memory_block->_inpool) {
		// 加锁
		std::lock_guard<std::mutex> lock(_mutex);
		// 先将该内存块的引用计数减1,然后判断引用计数是否大于1,如果大于1那么不释放直接return
		if (--memory_block->_nRef != 0) { return; }
		// 释放内存的时候将_pHeader前移,与申请时相反
		memory_block->_next = _cell_header;
		_cell_header = memory_block;
	} else {
		if (--memory_block->_nRef != 0) { return; }
		free(memory_block);
	}
}

// 返回内存管理的引用
MemoryManage& MemoryManage::get_instance() {
	// 单例模式  静态
	static MemoryManage memory_manage;
	return memory_manage;
}

// 申请内存
void* MemoryManage::mm_alloc_memory(size_t size) {
	if (size <= MAX_MEMORY_SIZE) {
		return _memory_array[size]->ma_alloc_memory(size);
	}
	else {
		MemoryBlock* memory_retrun = (MemoryBlock*)malloc(size + sizeof(MemoryBlock));
		memory_retrun->_inpool = false;
		memory_retrun->_nId = -1;
		memory_retrun->_nRef = 1;
		// 这个不属于内存处管理,所以设置为nullptr
		memory_retrun->_alloc = nullptr;
		memory_retrun->_next = nullptr;
		// xPrintf("mm_alloc_memory: %llx, id=%d, size=%d\n", memory_retrun, memory_retrun->_nId, size);
		return (char*)memory_retrun + sizeof(MemoryBlock);
	}
}

// 释放内存
void MemoryManage::mm_free_memory(void* memory) {
	MemoryBlock* memory_block = (MemoryBlock*)((char*)memory - sizeof(MemoryBlock));
	// xPrintf("mm_alloc_memory: %llx, id=%d\n", memory_block, memory_block->_nId);
	if (memory_block->_inpool) {
		memory_block->_alloc->ma_free_memory(memory);
	} else {
		if (--memory_block->_nRef == 0) {
			free(memory_block);
		}
	}
}

// 增加内存块的引用计数
void MemoryManage::add_ref(void* memory) {
	MemoryBlock* memory_block = (MemoryBlock*)((char*)memory - sizeof(MemoryBlock));
	++memory_block->_nRef;
}

// 初始化内存池映射数组
void MemoryManage::init_memory_array(int nbegin, int nend, MemoryAlloc* memory) {
	for (int n = nbegin; n <= nend; n++) {
		_memory_array[n] = memory;
	}
}
posted @ 2023-10-14 13:21  洋綮  阅读(33)  评论(0)    收藏  举报