allocate重写简要
- 一般STL库里的容器都会使用allocator来分配内存
- 实现自己的allocator可以达到让容器使用自身的内存管理
- 实现allocator不必重载allocator类,随便开一个新类即可
- allocator有五个必须有的函数
- allocate: 用于开辟内存,功能类似operator new
- deallocate: 回收内存,功能类似operator delete
- construct: 调用构造函数
- destroy: 调用释构函数
- 重绑用的拷贝函数
template <typename T>
class SharedMemAlloc {
public:
using value_type = T;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
using size_type = size_t;
SharedMemAlloc(){
std::cout << "do create SharedMemAlloc!!!" << std::endl;
}
// 重绑用的构造函数
template <class _Other>
constexpr SharedMemAlloc(const SharedMemAlloc<_Other>&) noexcept {}
inline pointer allocate(size_type _Count, const void* _Hint = nullptr) {
int total = _Count * sizeof(T) / sizeof(char);
std::cout << "trying to SharedMemAlloc allocate:" << _Count << ", type size:" << sizeof(T) << " Total:" << total << std::endl;
pointer ptr = (pointer)EDataChunk::instance().allocate(total);
if (!ptr)
throw std::exception("fail to allocate memory!!!!");
return ptr;
}
inline void deallocate(pointer _Ptr, size_type _Count){
EDataChunk::instance().deallocate((char*)_Ptr);
}
// construction/destruction
inline void construct(pointer p, const T& t) {
new(p) T(t);
}
inline void destroy(pointer p) {
p->~T();
}
};
简单的内存管理
- 一般来说,自己写的内存管理需要自己决定连续地址的内存分配问题,一般称这为多级内存管理, allocate只是其中一级。这里示范一下简单的内存管理
- 先把申请一块很大的内存
- 把内存切成一个个固定大小的
- 每次申请时,遍历找没有使用的块
- 如果块的大小不够,就往后块连续申请,直到大小足够
struct EDataChunkInfo {
char* ptr = nullptr;
int used_count = 0;
};
class EDataChunk {
public:
const int one_chunk_size = 64;
void init(char* datas, int size) {
this->all_datas = datas;
this->total_size = size;
this->create_data_chunks();
}
void uninit() {
// check all data is release!!!
for (auto it : this->pages) {
if (it.used_count != 0)
throw std::exception("Fail unrelease memory!!!!!");
}
this->pages.clear();
this->all_datas = nullptr;
this->total_size = 0;
}
void create_data_chunks() {
int cur = 0;
char* last_ptr = all_datas;
while (cur + one_chunk_size <= total_size) {
pages.push_back(EDataChunkInfo{ last_ptr, false });
last_ptr += one_chunk_size;
cur += one_chunk_size;
}
}
inline char* allocate(int size) {
for (auto it = pages.begin(); it != pages.end();) {
if (it->used_count > 0) {
it += it->used_count;
}
else {
int cur_size = one_chunk_size;
int count = 1;
auto cur_it = it;
for (; it != pages.end() && cur_size < size; ++it, cur_size += one_chunk_size, ++count) {
}
if (cur_size >= size) {
cur_it->used_count = count;
return cur_it->ptr;
}
}
}
return nullptr;
}
inline void deallocate(char* ptr) {
for (auto it = pages.begin(); it != pages.end(); ++it) {
if (it->ptr == ptr) {
std::cout << "deallocate memory: "<< it->ptr << ", " << it->used_count << " byte size:" << it->used_count * one_chunk_size << std::endl;
it->used_count = 0;
break;
}
}
}
static EDataChunk& instance() {
static EDataChunk g_inst;
return g_inst;
}
protected:
std::vector<EDataChunkInfo> pages;
int total_size = 0;
char* all_datas = nullptr;
};
使用方式
使用自己写的allocate后
EDataChunk::instance().init((char*)lpBase, BUFF_SIZE);
{
char* test_ptr = EDataChunk::instance().allocate(sizeof(MyIntVector));
MyIntVector* test_vec = new(test_ptr) MyIntVector(512, 0);//
test_vec->resize(10);
test_vec->push_back(2131);
test_vec->push_back(21);
test_vec->push_back(31);
test_vec->push_back(131);
test_vec->push_back(213);
test_vec->~MyIntVector();
EDataChunk::instance().deallocate(test_ptr);
}
EDataChunk::instance().uninit();
结果如下:
do create SharedMemAlloc!!!
trying to SharedMemAlloc allocate:1, type size:8 Total:8
trying to SharedMemAlloc allocate:512, type size:4 Total:2048
Do create shared buff!!!:[0,0,0,0,0,0,0,0,0,0,2131,21,31,131,213]
deallocate memory: 8192128page count: 32, byte size:2048
deallocate memory: 8192064page count: 1, byte size:64
deallocate memory: 8192000page count: 1, byte size:64