add my memory pool

This commit is contained in:
ouczbs 2024-11-13 16:37:15 +08:00
parent ae1f0a4b60
commit 3940805f0e
9 changed files with 393 additions and 111 deletions

View File

@ -24,6 +24,7 @@ namespace api
Guid(string_view str) noexcept : Guid{str.data()} {}
USING_OVERLOAD_CTOR(Guid, const char*)
UFUNCTION({}, ref = USING_CTOR_NAME)
Guid(const std::string& str) noexcept : Guid(str.data()){}
Guid(const char* str) noexcept
: Guid{}
{

View File

@ -1,9 +1,7 @@
#pragma once
#include <vector>
#include <memory_resource>
constexpr inline size_t meta_align_size(size_t size, size_t alignment = 8) {
return (size + alignment - 1) / alignment * alignment;
};
#include "memory/type.h"
namespace pmr {
using std::pmr::unsynchronized_pool_resource;
using std::pmr::memory_resource;
@ -50,5 +48,9 @@ inline void* operator new(size_t size, pmr::FrameAllocatorPool* pool, size_t ali
size = (size + alignment - 1) & ~(alignment - 1);
return pool->allocate(size, alignment);
}
//全局生命周期,不回收内存
//局部生命周期,每帧回收内存
ZLIB_API extern pmr::FrameAllocatorPool* MetaGlobalPool();
ZLIB_API extern pmr::FrameAllocatorPool* GlobalPool();
ZLIB_API extern pmr::FrameAllocatorPool* FramePool();
#include "frame_allocator.inl"
#include "memory.inl"

View File

@ -12,10 +12,6 @@ namespace pmr {
size_t space = capacity - offset;
void* ptr = buffer + offset;
if (bytes > capacity) {
if (std::align(alignment, bytes, ptr, space)) {
offset = capacity - space + bytes;
return ptr;
}
throw std::bad_alloc();
}
if (std::align(alignment, bytes, ptr, space)) {
@ -47,7 +43,6 @@ namespace pmr {
count = count > 0 ? count : 1;
allocators.erase(allocators.begin() + count, allocators.end());
}
#ifdef ZLIB_API_VAL //内存分配和释放必须位于同一模块(DLL)
inline FrameAllocator& FrameAllocator::operator=(FrameAllocator&& o)noexcept
{
std::construct_at(this, std::forward<FrameAllocator&&>(o));
@ -68,5 +63,4 @@ namespace pmr {
if (buffer)
delete[] buffer;
}
#endif
};

View File

@ -0,0 +1,99 @@
#pragma once
#include "frame_allocator.h"
#include "memory/memory_pool.h"
ZLIB_API inline pmr::FrameAllocatorPool* MetaGlobalPool() {
static pmr::FrameAllocatorPool* globalPool = new pmr::FrameAllocatorPool();
return globalPool;
}
ZLIB_API inline pmr::FrameAllocatorPool* GlobalPool() {
static pmr::FrameAllocatorPool* globalPool = new pmr::FrameAllocatorPool();
return globalPool;
}
ZLIB_API inline pmr::FrameAllocatorPool* FramePool() {
static pmr::FrameAllocatorPool* framePool = new pmr::FrameAllocatorPool();
return framePool;
}
namespace pmr {
inline MemoryPoolManager* pMainPool;
inline BlockAllocator* pMetaAlloc;
void CleanMainMemPool() {
if (!pMainPool) return;
pMainPool->~MemoryPoolManager();
pMetaAlloc->~BlockAllocator();
}
void* meta_malloc(size_t bytes, size_t alignment)
{
if (bytes > META_BLOCK_EMEM_SIZE * MAX_BLOCK_ELEM_GROUP_N || !pMetaAlloc->try_allocate(bytes)) {
return pMainPool->do_allocate(bytes, alignment);
}
using MemBlock = BlockAllocator::MemBlock;
bytes += sizeof(MemBlock);
MemBlock* pBlock = (MemBlock*)pMetaAlloc->do_allocate(bytes, alignment);
new(pBlock)MemBlock(bytes);
return (char*)pBlock + sizeof(MemBlock);
}
void meta_free(void* ptr)
{
if (!ptr) {
return;
}
using MemBlock = BlockAllocator::MemBlock;
MemBlock* pBlock = (MemBlock*)((char*)ptr - sizeof(MemBlock));
if (!pBlock) {
pMainPool->do_deallocate(ptr);
return;
}
pMetaAlloc->do_deallocate(ptr, pBlock->size, 0);
}
}
namespace pmr {
struct MemPoolWrap {
inline static char AllocData[sizeof(BlockAllocator)];
char pMemory[sizeof(MemoryPoolManager)];
bool isMainTread;
MemPoolWrap() {
isMainTread = !pMainPool;
if (isMainTread) {
pMainPool = (MemoryPoolManager*)&pMemory;
pMetaAlloc = (BlockAllocator*)&AllocData;
std::construct_at(pMetaAlloc, MEMORY_BLOCK_SIZE, META_BLOCK_EMEM_SIZE);
std::atexit(pmr::CleanMainMemPool);
}
std::construct_at((MemoryPoolManager*)&pMemory);
}
~MemPoolWrap() {
auto pool = (MemoryPoolManager*)&pMemory;
if (!isMainTread) {//主线程最后析构
pool->~MemoryPoolManager();
}
}
MemoryPoolManager* operator->() {
return (MemoryPoolManager*)&pMemory;
}
};
}
thread_local pmr::MemPoolWrap MemPool;
//#define mempool_allocate(...) MemPool->allocate(__VA_ARGS__);
//#define mempool_deallocate(ptr) MemPool->deallocate(ptr, 0);
void* mempool_allocate(size_t size, size_t align = 8) {
return MemPool->do_allocate(size, align);
}
void mempool_deallocate(void* ptr) {
return MemPool->do_deallocate(ptr);
}
void* operator new(size_t size) {
return mempool_allocate(size);
}
// 默认对齐方式 delete
void operator delete(void* ptr) noexcept {
mempool_deallocate(ptr);
}
// Array new and delete
void* operator new[](size_t size) {
return mempool_allocate(size);
}
void operator delete[](void* ptr) noexcept {
mempool_deallocate(ptr);
}

View File

@ -1,96 +0,0 @@
#pragma once
#include "singleton.h"
//全局生命周期,不回收内存
//局部生命周期,每帧回收内存
ZLIB_API extern pmr::FrameAllocatorPool* MetaGlobalPool();
ZLIB_API extern pmr::FrameAllocatorPool* GlobalPool();
ZLIB_API extern pmr::FrameAllocatorPool* FramePool();
extern void* operator new(std::size_t size);
extern void operator delete(void* ptr) noexcept;
extern void* operator new[](std::size_t size);
extern void operator delete[](void* ptr) noexcept;
#ifdef ZLIB_API_VAL
ZLIB_API inline pmr::FrameAllocatorPool* MetaGlobalPool() {
static pmr::FrameAllocatorPool* globalPool = new pmr::FrameAllocatorPool();
return globalPool;
}
ZLIB_API inline pmr::FrameAllocatorPool* GlobalPool() {
static pmr::FrameAllocatorPool* globalPool = new pmr::FrameAllocatorPool();
return globalPool;
}
ZLIB_API inline pmr::FrameAllocatorPool* FramePool() {
static pmr::FrameAllocatorPool* framePool = new pmr::FrameAllocatorPool();
return framePool;
}
struct MemPoolWrap {
char pMemory[sizeof(pmr::unsynchronized_pool_resource)];
uint32_t id;
MemPoolWrap() {
static uint32_t sThreadId = 0;
id = sThreadId++;
std::construct_at((pmr::unsynchronized_pool_resource*)&pMemory);
}
~MemPoolWrap() {
auto pool = (pmr::unsynchronized_pool_resource*)&pMemory;
if (id) {//主线程不能析构,会有顺序问题
pool->~unsynchronized_pool_resource();
}
}
pmr::unsynchronized_pool_resource* operator->() {
return (pmr::unsynchronized_pool_resource*)&pMemory;
}
};
thread_local MemPoolWrap MemPool;
//#define mempool_allocate(...) MemPool->allocate(__VA_ARGS__);
//#define mempool_deallocate(ptr) MemPool->deallocate(ptr, 0);
#define MEM_BLOCK_BEGIN_MASK 0x5555
#define MEM_BLOCK_END_MASK 0xAAAA
struct MemBlock {
uint16_t begin_mask;
uint16_t size;
uint16_t size_mask;
uint16_t end_mask;
};
void* mempool_allocate(size_t size, size_t align = alignof(std::max_align_t)) {
if (size < 16) {
return MemPool->allocate(size, align);
}
size_t all_size = sizeof(MemBlock) + meta_align_size(size, align);
MemBlock* pBlock = (MemBlock*)MemPool->allocate(all_size, align);
pBlock->begin_mask = MEM_BLOCK_BEGIN_MASK;
pBlock->size = size;
pBlock->size_mask = size;
pBlock->end_mask = MEM_BLOCK_END_MASK;
return (char*)pBlock + sizeof(MemBlock);
}
void mempool_deallocate(void* ptr) {
if (!ptr) {
return;
}
MemBlock* pBlock = (MemBlock*)((char*)ptr - sizeof(MemBlock));
if (pBlock->begin_mask == MEM_BLOCK_BEGIN_MASK && pBlock->end_mask == MEM_BLOCK_END_MASK
&& pBlock->size == pBlock->size_mask) {
MemPool->deallocate(pBlock, sizeof(MemBlock) + pBlock->size);
}
else {
MemPool->deallocate(ptr, 0);
}
}
void* operator new(size_t size) {
return mempool_allocate(size);
}
// 默认对齐方式 delete
void operator delete(void* ptr) noexcept {
mempool_deallocate(ptr);
}
// Array new and delete
void* operator new[](size_t size) {
return mempool_allocate(size);
}
void operator delete[](void* ptr) noexcept {
mempool_deallocate(ptr);
}
#endif //

View File

@ -0,0 +1,267 @@
#pragma once
#include "type.h"
#include <bit>
#include <memory_resource>
#include <iostream>
#include <numeric>
#include <windows.h>
namespace pmr {
using std::pmr::memory_resource;
class MemoryPagePool {
public:
static void* do_allocate(size_t bytes, size_t alignment) {
void* ptr = (void*)VirtualAlloc(NULL, bytes, MEM_COMMIT, PAGE_READWRITE);
return ptr;
}
static void do_deallocate(void* ptr) {
if (!ptr) {
return;
}
VirtualFree(ptr, 0, MEM_RELEASE);
}
};
class BlockAllocator : public memory_resource {
private:
friend class MemoryPoolManager;
uint16_t* m_stack;
uint8_t* m_bitmap; // 位图起始地址
char* m_data;
uint16_t m_block_size;
uint16_t m_block_count;
uint16_t m_used_count;
uint16_t m_head;
public:
struct MemBlock {
uint16_t size;
uint16_t begin_mask;
uint16_t end_mask;
uint16_t padding3;
MemBlock(size_t bytes) : size(bytes)
, begin_mask(0x5555)
, end_mask(0xAAAA) {}
operator bool() {
return begin_mask == 0x5555 && end_mask == 0xAAAA;
}
};
BlockAllocator(size_t MemorySize, uint16_t block_size):m_block_size(block_size){
uint16_t count = 8 * MemorySize / (8 * block_size + 8 * sizeof(uint16_t) + 1);
uint16_t bitmap_size = (count + 7) / 8;
size_t offset = meta_align_size(count * 2 + bitmap_size, 8);
if (offset + count * block_size > MemorySize) {
count--;
offset = meta_align_size(count * 2 + bitmap_size, 8);
}
m_stack = (uint16_t*)MemoryPagePool::do_allocate(MemorySize, 8);
m_bitmap = (uint8_t*)m_stack + count * 2;
m_data = (char*)m_stack + offset;
std::memset(m_bitmap, 0, bitmap_size);
std::iota(m_stack, m_stack + count, 0);
m_head = 0;
m_used_count = 0;
m_block_count = count;
}
~BlockAllocator() {
if (m_stack) {
MemoryPagePool::do_deallocate(m_stack);
}
m_stack = nullptr;
}
bool try_allocate(size_t bytes) {
return bytes <= m_block_size || m_block_count - m_block_size >= MAX_BLOCK_ELEM_GROUP_N;
}
bool invert_bitmap(uint16_t bit_pos, uint8_t flag) {
size_t index = bit_pos / 8;
uint8_t invert_mask = 1 << (7 - bit_pos % 8);
m_bitmap[index] ^= invert_mask;
return flag ? (m_bitmap[index] & invert_mask) == invert_mask :
(m_bitmap[index] & invert_mask) == 0;
}
bool invert_bitmap_group(uint16_t bit_pos, uint8_t count, uint8_t flag) {
size_t index = bit_pos / 8;
uint8_t offset = bit_pos % 8;
uint8_t left_mask = 0xff >> offset;//00011111
offset = (16 - offset - count) % 8;
uint8_t right_mask = 0xff << offset;//11111110
if (offset + count <= 8) {
uint8_t mask = left_mask & right_mask;//00011110
uint8_t mask_result = flag ? mask : 0;
m_bitmap[index] ^= mask;
return (m_bitmap[index] & mask) == mask_result;
}
m_bitmap[index] ^= left_mask;
m_bitmap[index + 1] ^= right_mask;
uint8_t left_mask_result = flag ? left_mask : 0;
uint8_t right_mask_result = flag ? right_mask : 0;
return (m_bitmap[index] & left_mask) == left_mask_result && (m_bitmap[index + 1] & right_mask) == right_mask_result;
}
void* do_allocate(size_t bytes, size_t alignment)override {
uint16_t index = m_stack[m_head];
uint16_t count = (bytes + m_block_size - 1) / m_block_size;
if (count == 1 && !invert_bitmap(index, 1)) {
invert_bitmap(index, 0);
throw std::runtime_error("Error: Attempting to allocate an already allocated block.");
}
if (count > 1 && !invert_bitmap_group(index, count, 1)) {
invert_bitmap_group(index, count, 1);
throw std::runtime_error("Error: Attempting to allocate an already allocated block group.");
}
m_used_count += count;
m_head = (m_head + count) % m_block_count;
return m_data + m_block_size * index;
}
void do_deallocate(void* ptr, size_t bytes, size_t alignment) override {
uint16_t index = size_t((char*)ptr - m_data) / m_block_size;
uint16_t count = (bytes + m_block_size - 1) / m_block_size;
if (count == 1) {
if (!invert_bitmap(index, 0)) {
invert_bitmap(index, 0);
throw std::runtime_error("Error: Double deallocation attempt!");
}
m_stack[(m_head + m_block_count - m_used_count) % m_block_count] = index;
m_used_count--;
return;
}
if (count > 1 && !invert_bitmap_group(index, count, 0)) {
invert_bitmap_group(index, count, 0);
throw std::runtime_error("Error: Double deallocation group attempt!");
}
alignment = (m_head + m_block_count - m_used_count) % m_block_count;
if (alignment + count < m_block_count) [[likely]] {
std::iota(m_stack + alignment, m_stack + alignment + count, index);
}
else [[unlikely]] {
for (uint16_t i = 0; i < count; i++) {
m_stack[(alignment + i) % m_block_count] = index + i;
}
}
m_used_count -= count;
}
bool do_is_equal(const memory_resource& other) const noexcept override { return this == &other; };
};
class MemoryPoolManager{
public:
struct MemBlock {
uint32_t begin_mask;
uint16_t size;
uint8_t index;
uint8_t alloc_index;
uint16_t size_mask;
uint8_t index_mask;
uint8_t alloc_index_mask;
uint32_t end_mask;
MemBlock(size_t bytes, uint8_t index, uint8_t alloc_index)
: size(bytes)
, size_mask(bytes)
, index(index)
, alloc_index(alloc_index)
, begin_mask(0x55555555)
, end_mask(0xAAAAAAAA){
}
operator bool() {
return size && (uint32_t)size == (uint32_t)size_mask
&& begin_mask == 0x55555555
&& end_mask == 0xAAAAAAAA;
}
};
struct AllocatorPtr {
BlockAllocator* alloc;
AllocatorPtr* next;
AllocatorPtr() :alloc(nullptr), next(nullptr){}
operator bool() {
return alloc;
}
BlockAllocator* operator->() {
return alloc;
}
~AllocatorPtr() {
if (alloc) {
alloc->~BlockAllocator();
}
if (next) {
next->~AllocatorPtr();
meta_free(this);
}
}
};
private:
AllocatorPtr mAllocators[MAX_BLOCK_ELEM_SIZE_N] = {};
public:
MemoryPoolManager(){}
~MemoryPoolManager() {
for (uint32_t i = 0; i < MAX_BLOCK_ELEM_SIZE_N; i++) {
mAllocators[i].~AllocatorPtr();
meta_free(mAllocators[i].alloc);
}
}
int find_pool_index(size_t bytes) {
size_t block_size = std::bit_ceil(bytes);
int index = __builtin_ctz(block_size);
if (index < MAX_BLOCK_ELEM_SIZE_N) {
int count = ((bytes << 3) + block_size - 1) / block_size;
if (count >= 7) {
return index;
}
if (count >= 6) {
return index - 2;
}
return index > 7 ? index - 3 : 4;
}
return index;
}
void* do_allocate(size_t bytes, size_t alignment) {
size_t bytes_block = bytes + sizeof(MemBlock);
int index = find_pool_index(bytes_block);
if (index < MAX_BLOCK_ELEM_SIZE_N) {
uint16_t alloc_index = 0;
AllocatorPtr& pAlloc = mAllocators[index];
if (!pAlloc) {
pAlloc.alloc = (BlockAllocator*)meta_malloc(sizeof(BlockAllocator));
new (pAlloc.alloc) BlockAllocator(MEMORY_BLOCK_SIZE, 1 << index);
return do_allocate_block(pAlloc.alloc, bytes_block, index, alloc_index);
}
while(pAlloc) {
if (pAlloc->try_allocate(bytes_block)) {
return do_allocate_block(pAlloc.alloc, bytes_block, index, alloc_index);
}
if (!pAlloc.next) {
void* pMemory = meta_malloc(sizeof(AllocatorPtr) + sizeof(BlockAllocator));
AllocatorPtr* next = new(pMemory) AllocatorPtr();
next->alloc = new((char*)pMemory + sizeof(AllocatorPtr)) BlockAllocator(MEMORY_BLOCK_SIZE, 1 << index);
pAlloc.next = next;
return do_allocate_block(next->alloc, bytes_block, index, alloc_index);
}
pAlloc = *pAlloc.next;
alloc_index++;
}
throw std::bad_alloc();
}
return malloc(bytes);
}
void* do_allocate_block(BlockAllocator* alloc, size_t bytes, uint8_t index, uint8_t alloc_index) {
MemBlock* pBlock = (MemBlock*)alloc->do_allocate(bytes, 0);
new(pBlock)MemBlock(bytes, index, alloc_index);
return (char*)pBlock + sizeof(MemBlock);
}
void do_deallocate(void* ptr) {
if (!ptr) {
return;
}
MemBlock* pBlock = (MemBlock*)((char*)ptr - sizeof(MemBlock));
if (!pBlock) {
free(ptr);
return;
}
AllocatorPtr& pAlloc = mAllocators[pBlock->index];
uint16_t alloc_index = pBlock->alloc_index + 1;
while (alloc_index && pAlloc) {
alloc_index--;
if (!alloc_index) {
pAlloc->do_deallocate(pBlock, pBlock->size, 0);
return;
}
pAlloc = *pAlloc.next;
}
throw std::runtime_error("Warning: deallocate erorr!!!");
}
};
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "singleton.h"
#define MEMORY_BLOCK_SIZE 1048576
#define META_BLOCK_EMEM_SIZE 16
#define MAX_BLOCK_ELEM_SIZE_N 16
#define MAX_BLOCK_ELEM_GROUP_N 8
constexpr inline size_t meta_align_size(size_t size, size_t alignment = 8) {
return (size + alignment - 1) / alignment * alignment;
};
namespace pmr {
void* meta_malloc(size_t bytes, size_t alignment = 16);
void meta_free(void* ptr);
}
extern void* operator new(std::size_t size);
extern void operator delete(void* ptr) noexcept;
extern void* operator new[](std::size_t size);
extern void operator delete[](void* ptr) noexcept;

View File

@ -1,9 +1,7 @@
#ifndef ZLIB_API_VAL
#define ZLIB_API_VAL 1
#include "pmr/frame_allocator.h"
#include "pmr/name.h"
#include "pmr/memory.h"
#include "refl/detail/uclass.inl"
#endif // !ZLIB_API_VAL

View File

@ -1,8 +1,8 @@
#define ZLIB_API
#define ZLIB_API_VAL
#define CORE_API
#define CORE_API_VAL
#include "archive/pch.h"
#include "pmr/memory.h"
#include "test_refl.h"
using namespace api;
using namespace std;