From a6458a82c01ee3f157d91af82e7c6ce436bfdfc2 Mon Sep 17 00:00:00 2001 From: ouczbs Date: Sat, 16 Nov 2024 17:54:37 +0800 Subject: [PATCH] add xmalloc --- .gitignore | 1 - engine/3rdparty/memalloc/include/memalloc.h | 24 ++ .../3rdparty/memalloc/include/memory_pool.h | 282 ++++++++++++++++++ .../memalloc/include/memory_pool_debug.h | 35 +++ engine/3rdparty/memalloc/src/memalloc.cpp | 105 +++++++ engine/3rdparty/memalloc/xmake.lua | 7 + .../singleton/include/singleton.h | 0 .../singleton/src/singleton.cpp | 0 .../engine => 3rdparty}/singleton/xmake.lua | 2 +- .../xmalloc/include/xmalloc_new_delete.h | 35 +++ .../3rdparty/xmalloc/include/xmalloc_type.h | 13 + engine/3rdparty/xmalloc/src/xmalloc_me.cpp | 20 ++ engine/3rdparty/xmalloc/src/xmalloc_mi.cpp | 29 ++ engine/3rdparty/xmalloc/xmake.lua | 8 + .../engine/zlib/include/pmr/frame_allocator.h | 1 - .../engine/zlib/include/xmemory_type.h | 37 --- engine/modules/render/vulkan/src/module.cpp | 1 + engine/modules/xmake.lua | 2 +- engine/src/engine/api.cpp | 1 + engine/src/engine/mimalloc.cpp | 16 - engine/xmake.lua | 2 +- game/zworld/editor/zworld_editor.cpp | 5 +- game/zworld/src/main.cpp | 1 + game/zworld/xmake.lua | 2 +- 24 files changed, 569 insertions(+), 60 deletions(-) create mode 100644 engine/3rdparty/memalloc/include/memalloc.h create mode 100644 engine/3rdparty/memalloc/include/memory_pool.h create mode 100644 engine/3rdparty/memalloc/include/memory_pool_debug.h create mode 100644 engine/3rdparty/memalloc/src/memalloc.cpp create mode 100644 engine/3rdparty/memalloc/xmake.lua rename engine/{modules/engine => 3rdparty}/singleton/include/singleton.h (100%) rename engine/{modules/engine => 3rdparty}/singleton/src/singleton.cpp (100%) rename engine/{modules/engine => 3rdparty}/singleton/xmake.lua (82%) create mode 100644 engine/3rdparty/xmalloc/include/xmalloc_new_delete.h create mode 100644 engine/3rdparty/xmalloc/include/xmalloc_type.h create mode 100644 engine/3rdparty/xmalloc/src/xmalloc_me.cpp create mode 100644 engine/3rdparty/xmalloc/src/xmalloc_mi.cpp create mode 100644 engine/3rdparty/xmalloc/xmake.lua delete mode 100644 engine/modules/engine/zlib/include/xmemory_type.h delete mode 100644 engine/src/engine/mimalloc.cpp diff --git a/.gitignore b/.gitignore index 08e8cec..010a1eb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ build/ vsxmake*/ /tools -engine/3rdparty/ diff --git a/engine/3rdparty/memalloc/include/memalloc.h b/engine/3rdparty/memalloc/include/memalloc.h new file mode 100644 index 0000000..30e5c25 --- /dev/null +++ b/engine/3rdparty/memalloc/include/memalloc.h @@ -0,0 +1,24 @@ +#pragma once +#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 +#define MEM_CALLSTACK_DEBUG_N 16 +#define MEMORY_ALIGN_N 16 +namespace pmr { + void* meta_malloc(size_t bytes, size_t alignment = MEMORY_ALIGN_N); + void meta_free(void* ptr); +} + +MEMALLOC_API void* me_malloc(size_t size); +MEMALLOC_API void* me_malloc_nothrow(size_t size) noexcept; +MEMALLOC_API void me_free(void* p) noexcept; +#if (__cplusplus >= 201402L || _MSC_VER >= 1916) +MEMALLOC_API void me_free_size(void* p, size_t size) noexcept; +#endif +#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) +MEMALLOC_API void* me_malloc_aligned(size_t size, size_t alignment); +MEMALLOC_API void* me_malloc_aligned_nothrow(size_t size, size_t alignment) noexcept; +MEMALLOC_API void me_free_size_aligned(void* p, size_t size, size_t alignment) noexcept; +MEMALLOC_API void me_free_aligned(void* p, size_t alignment) noexcept; +#endif \ No newline at end of file diff --git a/engine/3rdparty/memalloc/include/memory_pool.h b/engine/3rdparty/memalloc/include/memory_pool.h new file mode 100644 index 0000000..ebc7ce8 --- /dev/null +++ b/engine/3rdparty/memalloc/include/memory_pool.h @@ -0,0 +1,282 @@ +#pragma once +#include "memalloc.h" +#include +#include +#include +#include +#include +constexpr inline size_t meta_align_size(size_t size, size_t alignment) { + return (size + alignment - 1) / alignment * alignment; +}; +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; + } + }; + friend void dumpMetaMemoryLeaks(BlockAllocator* metaAlloc); + 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, MEMORY_ALIGN_N); + if (offset + count * block_size > MemorySize) { + count--; + offset = meta_align_size(count * 2 + bitmap_size, MEMORY_ALIGN_N); + } + m_stack = (uint16_t*)MemoryPagePool::do_allocate(MemorySize, MEMORY_ALIGN_N); + 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 empty() { + return m_used_count == 0; + } + 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 { +#ifdef API_DEBUG + void* debug_stack[MEM_CALLSTACK_DEBUG_N]; +#endif // API_DEBUG + 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: + friend void dumpMemoryPoolLeaks(MemoryPoolManager* memPool); + 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); +#ifdef API_DEBUG + // 捕获当前堆栈 + uint16_t n = CaptureStackBackTrace(0, MEM_CALLSTACK_DEBUG_N, pBlock->debug_stack, nullptr); +#endif // API_DEBUG + 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!!!"); + } + }; +} \ No newline at end of file diff --git a/engine/3rdparty/memalloc/include/memory_pool_debug.h b/engine/3rdparty/memalloc/include/memory_pool_debug.h new file mode 100644 index 0000000..5b2e4df --- /dev/null +++ b/engine/3rdparty/memalloc/include/memory_pool_debug.h @@ -0,0 +1,35 @@ +#pragma once +#include "memory_pool.h" +namespace pmr { + inline void dumpMemoryPoolLeaks(MemoryPoolManager* memPool) { + auto& mAllocators = memPool->mAllocators; + for (uint32_t i = 0; i < MAX_BLOCK_ELEM_SIZE_N; i++) { + auto& pAlloc = mAllocators[i]; + if (pAlloc && !pAlloc->empty()) { + dumpMetaMemoryLeaks(pAlloc.alloc); + } + } + } + inline void dumpMetaMemoryLeaks(BlockAllocator* metaAlloc) { + if (metaAlloc->empty()) { + return; + } + uint64_t* bitmap = (uint64_t*)metaAlloc->m_bitmap; + size_t use_count = (metaAlloc->m_head + 63 )/ 64; + for (size_t i = 0; i < use_count; i++) { + uint64_t chunk = bitmap[i]; + while (chunk != 0) { + int offset = __builtin_ctz(chunk); // 找到最低有效位 "1" 的位置 + void* ptr = metaAlloc->m_data + metaAlloc->m_block_size * (i * 64 + 63 - offset); + MemoryPoolManager::MemBlock* pBlock = (MemoryPoolManager::MemBlock*)((char*)ptr - sizeof(MemoryPoolManager::MemBlock)); + if (*pBlock) { + metaAlloc->do_deallocate(pBlock, pBlock->size, 0); + chunk = bitmap[i]; + } + else { + chunk &= chunk - 1; // 清除最低有效位的“1” + } + } + } + } +} \ No newline at end of file diff --git a/engine/3rdparty/memalloc/src/memalloc.cpp b/engine/3rdparty/memalloc/src/memalloc.cpp new file mode 100644 index 0000000..4f662aa --- /dev/null +++ b/engine/3rdparty/memalloc/src/memalloc.cpp @@ -0,0 +1,105 @@ +//内存设计有问题,溜了溜了。还是先学习mimalloc吧 +#include "memory_pool_debug.h" +namespace pmr { + inline MemoryPoolManager* pMainPool; + inline BlockAllocator* pMetaAlloc; + void CleanMainMemPool() { + if (!pMainPool) return; + dumpMemoryPoolLeaks(pMainPool); + pMainPool->~MemoryPoolManager(); + dumpMetaMemoryLeaks(pMetaAlloc); + 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(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; + +MEMALLOC_API void* me_malloc(size_t size) +{ + return MemPool->do_allocate(size, MEMORY_ALIGN_N); +} + +MEMALLOC_API void* me_malloc_nothrow(size_t size) noexcept +{ + return MemPool->do_allocate(size, MEMORY_ALIGN_N); +} + +MEMALLOC_API void me_free(void* p) noexcept +{ + MemPool->do_deallocate(p); +} +#if (__cplusplus >= 201402L || _MSC_VER >= 1916) +MEMALLOC_API void me_free_size(void* p, size_t size) noexcept +{ + MemPool->do_deallocate(p); +} +#endif +#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) +MEMALLOC_API void* me_malloc_aligned(size_t size, size_t alignment) +{ + return MemPool->do_allocate(size, alignment); +} + +MEMALLOC_API void* me_malloc_aligned_nothrow(size_t size, size_t alignment) noexcept +{ + return MemPool->do_allocate(size, alignment); +} +MEMALLOC_API void me_free_aligned(void* p, size_t alignment) noexcept +{ + return MemPool->do_deallocate(p); +} +MEMALLOC_API void me_free_size_aligned(void* p, size_t size, size_t alignment) noexcept +{ + MemPool->do_deallocate(p); +} + +#endif \ No newline at end of file diff --git a/engine/3rdparty/memalloc/xmake.lua b/engine/3rdparty/memalloc/xmake.lua new file mode 100644 index 0000000..7eb3181 --- /dev/null +++ b/engine/3rdparty/memalloc/xmake.lua @@ -0,0 +1,7 @@ +target("memalloc") + set_group("3rdparty") + set_kind("shared") + add_rules("engine.api") + add_includedirs("include",{public = true}) + add_headerfiles("include/*.h") + add_files("src/*.cpp") \ No newline at end of file diff --git a/engine/modules/engine/singleton/include/singleton.h b/engine/3rdparty/singleton/include/singleton.h similarity index 100% rename from engine/modules/engine/singleton/include/singleton.h rename to engine/3rdparty/singleton/include/singleton.h diff --git a/engine/modules/engine/singleton/src/singleton.cpp b/engine/3rdparty/singleton/src/singleton.cpp similarity index 100% rename from engine/modules/engine/singleton/src/singleton.cpp rename to engine/3rdparty/singleton/src/singleton.cpp diff --git a/engine/modules/engine/singleton/xmake.lua b/engine/3rdparty/singleton/xmake.lua similarity index 82% rename from engine/modules/engine/singleton/xmake.lua rename to engine/3rdparty/singleton/xmake.lua index 9eec785..4be6758 100644 --- a/engine/modules/engine/singleton/xmake.lua +++ b/engine/3rdparty/singleton/xmake.lua @@ -1,6 +1,6 @@ target("singleton") set_kind("shared") - set_group("Engine/engine__comp") + set_group("3rdparty") add_rules("engine.api") add_includedirs("include", {public = true}) add_headerfiles("include/*.h") diff --git a/engine/3rdparty/xmalloc/include/xmalloc_new_delete.h b/engine/3rdparty/xmalloc/include/xmalloc_new_delete.h new file mode 100644 index 0000000..989a45d --- /dev/null +++ b/engine/3rdparty/xmalloc/include/xmalloc_new_delete.h @@ -0,0 +1,35 @@ +#pragma once +#if defined(__cplusplus) +#include +#include "xmalloc_type.h" +void operator delete(void* p) noexcept { xfree(p); }; +void operator delete[](void* p) noexcept { xfree(p); }; + +void operator delete (void* p, const std::nothrow_t&) noexcept { xfree(p); } +void operator delete[](void* p, const std::nothrow_t&) noexcept { xfree(p); } + +void* operator new(std::size_t n) noexcept(false) { return xmalloc(n); } +void* operator new[](std::size_t n) noexcept(false) { return xmalloc(n); } + +void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return xmalloc_nothrow(n); } +void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return xmalloc_nothrow(n); } + +#if (__cplusplus >= 201402L || _MSC_VER >= 1916) +void operator delete (void* p, std::size_t n) noexcept { xfree_size(p, n); }; +void operator delete[](void* p, std::size_t n) noexcept { xfree_size(p, n); }; +#endif + +#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) +void operator delete (void* p, std::align_val_t al) noexcept { xfree_aligned(p, static_cast(al)); } +void operator delete[](void* p, std::align_val_t al) noexcept { xfree_aligned(p, static_cast(al)); } +void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { xfree_size_aligned(p, n, static_cast(al)); }; +void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { xfree_size_aligned(p, n, static_cast(al)); }; +void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept { xfree_aligned(p, static_cast(al)); } +void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept { xfree_aligned(p, static_cast(al)); } + +void* operator new (std::size_t n, std::align_val_t al) noexcept(false) { return xmalloc_aligned(n, static_cast(al)); } +void* operator new[](std::size_t n, std::align_val_t al) noexcept(false) { return xmalloc_aligned(n, static_cast(al)); } +void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return xmalloc_aligned_nothrow(n, static_cast(al)); } +void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return xmalloc_aligned_nothrow(n, static_cast(al)); } +#endif +#endif diff --git a/engine/3rdparty/xmalloc/include/xmalloc_type.h b/engine/3rdparty/xmalloc/include/xmalloc_type.h new file mode 100644 index 0000000..0c7142c --- /dev/null +++ b/engine/3rdparty/xmalloc/include/xmalloc_type.h @@ -0,0 +1,13 @@ +#pragma once +XMALLOC_API void* xmalloc(size_t size); +XMALLOC_API void* xmalloc_nothrow(size_t size) noexcept; +XMALLOC_API void xfree(void* p) noexcept; +#if (__cplusplus >= 201402L || _MSC_VER >= 1916) +XMALLOC_API void xfree_size(void* p, size_t size) noexcept; +#endif +#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) +XMALLOC_API void xfree_size_aligned(void* p, size_t size, size_t alignment) noexcept; +XMALLOC_API void xfree_aligned(void* p, size_t alignment) noexcept; +XMALLOC_API void* xmalloc_aligned(size_t size, size_t alignment); +XMALLOC_API void* xmalloc_aligned_nothrow(size_t size, size_t alignment) noexcept; +#endif \ No newline at end of file diff --git a/engine/3rdparty/xmalloc/src/xmalloc_me.cpp b/engine/3rdparty/xmalloc/src/xmalloc_me.cpp new file mode 100644 index 0000000..54c4667 --- /dev/null +++ b/engine/3rdparty/xmalloc/src/xmalloc_me.cpp @@ -0,0 +1,20 @@ +#if 0 +#include "xmalloc_type.h" +#include "memalloc.h" +XMALLOC_API void* xmalloc(size_t size) { return mi_malloc(size); } +XMALLOC_API void* xmalloc_nothrow(size_t size) noexcept { return mi_new_nothrow(size); } + +XMALLOC_API void xfree(void* p) noexcept { mi_free(p); } + +#if (__cplusplus >= 201402L || _MSC_VER >= 1916) +XMALLOC_API void xfree_size(void* p, size_t size) noexcept { return mi_free_size(p, size); } +#endif + +#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) +XMALLOC_API void xfree_size_aligned(void* p, size_t size, size_t alignment) noexcept { return mi_free_size_aligned(p, size, alignment); } +XMALLOC_API void xfree_aligned(void* p, size_t alignment) noexcept { return mi_free_aligned(p, alignment); } + +XMALLOC_API void* xmalloc_aligned(size_t size, size_t alignment) { return mi_new_aligned(size, alignment); } +XMALLOC_API void* xmalloc_aligned_nothrow(size_t size, size_t alignment) noexcept { return mi_new_aligned_nothrow(size, alignment); } +#endif +#endif \ No newline at end of file diff --git a/engine/3rdparty/xmalloc/src/xmalloc_mi.cpp b/engine/3rdparty/xmalloc/src/xmalloc_mi.cpp new file mode 100644 index 0000000..1419693 --- /dev/null +++ b/engine/3rdparty/xmalloc/src/xmalloc_mi.cpp @@ -0,0 +1,29 @@ +#include "xmalloc_type.h" +#include "mimalloc.h" +void clean() { + // 强制垃圾回收并检查未释放的内存 + mi_stats_print(NULL); + mi_collect(true); +} +struct mi_exit_wrap { + mi_exit_wrap() { + std::atexit(clean); + } +}; +static mi_exit_wrap _mi_exit_wrap; +XMALLOC_API void* xmalloc(size_t size){return mi_malloc(size);} +XMALLOC_API void* xmalloc_nothrow(size_t size) noexcept{return mi_new_nothrow(size);} + +XMALLOC_API void xfree(void* p) noexcept{mi_free(p);} + +#if (__cplusplus >= 201402L || _MSC_VER >= 1916) +XMALLOC_API void xfree_size(void* p, size_t size) noexcept{return mi_free_size(p, size);} +#endif + +#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) +XMALLOC_API void xfree_size_aligned(void* p, size_t size, size_t alignment) noexcept{return mi_free_size_aligned(p, size, alignment);} +XMALLOC_API void xfree_aligned(void* p, size_t alignment) noexcept{return mi_free_aligned(p, alignment);} + +XMALLOC_API void* xmalloc_aligned(size_t size, size_t alignment) { return mi_new_aligned(size, alignment); } +XMALLOC_API void* xmalloc_aligned_nothrow(size_t size, size_t alignment) noexcept { return mi_new_aligned_nothrow(size, alignment); } +#endif \ No newline at end of file diff --git a/engine/3rdparty/xmalloc/xmake.lua b/engine/3rdparty/xmalloc/xmake.lua new file mode 100644 index 0000000..5d4267a --- /dev/null +++ b/engine/3rdparty/xmalloc/xmake.lua @@ -0,0 +1,8 @@ +target("xmalloc") + set_kind("shared") + set_group("3rdparty") + add_rules("engine.api") + add_includedirs("include", {public = true}) + add_headerfiles("include/*.h") + add_files("src/*.cpp") + add_packages("mimalloc") \ No newline at end of file diff --git a/engine/modules/engine/zlib/include/pmr/frame_allocator.h b/engine/modules/engine/zlib/include/pmr/frame_allocator.h index 41e71cc..75356d9 100644 --- a/engine/modules/engine/zlib/include/pmr/frame_allocator.h +++ b/engine/modules/engine/zlib/include/pmr/frame_allocator.h @@ -1,7 +1,6 @@ #pragma once #include #include -#include "xmemory_type.h" namespace pmr { using std::pmr::unsynchronized_pool_resource; using std::pmr::memory_resource; diff --git a/engine/modules/engine/zlib/include/xmemory_type.h b/engine/modules/engine/zlib/include/xmemory_type.h deleted file mode 100644 index 280b064..0000000 --- a/engine/modules/engine/zlib/include/xmemory_type.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -// ---------------------------------------------------------------------------- -// This header provides convenient overrides for the new and -// delete operations in C++. -// -// This header should be included in only one source file! -// -// On Windows, or when linking dynamically with mimalloc, these -// can be more performant than the standard new-delete operations. -// See -// --------------------------------------------------------------------------- -#if defined(__cplusplus) -extern void operator delete(void* p) noexcept; -extern void operator delete[](void* p) noexcept; - -extern void operator delete (void* p, const std::nothrow_t&) noexcept; -extern void operator delete[](void* p, const std::nothrow_t&) noexcept; - -#if (__cplusplus >= 201402L || _MSC_VER >= 1916) -extern void operator delete (void* p, std::size_t n) noexcept; -extern void operator delete[](void* p, std::size_t n) noexcept; -#endif - -#if (__cplusplus > 201402L || defined(__cpp_aligned_new)) -extern void operator delete (void* p, std::align_val_t al) noexcept; -extern void operator delete[](void* p, std::align_val_t al) noexcept; -extern void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept; -extern void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept; -extern void operator delete (void* p, std::align_val_t al, const std::nothrow_t&) noexcept; -extern void operator delete[](void* p, std::align_val_t al, const std::nothrow_t&) noexcept; - -extern void* operator new (std::size_t n, std::align_val_t al) noexcept(false); -extern void* operator new[](std::size_t n, std::align_val_t al) noexcept(false); -extern void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept; -extern void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept; -#endif -#endif \ No newline at end of file diff --git a/engine/modules/render/vulkan/src/module.cpp b/engine/modules/render/vulkan/src/module.cpp index c15c5c5..5508aea 100644 --- a/engine/modules/render/vulkan/src/module.cpp +++ b/engine/modules/render/vulkan/src/module.cpp @@ -1,3 +1,4 @@ +#include "xmalloc_new_delete.h" #include "vkn/module.h" #include "vkn/loader/vulkan_glsl_loader.h" #include "pmr/frame_allocator.h" diff --git a/engine/modules/xmake.lua b/engine/modules/xmake.lua index 734b6f3..f240223 100644 --- a/engine/modules/xmake.lua +++ b/engine/modules/xmake.lua @@ -29,7 +29,7 @@ function shared_module(name, owner, opt) set_group("Engine/"..owner.."__dyn") add_rules("engine.api") add_includedirs("include", {public = true}) - add_rules("engine.plugin", {file = opt and opt.file or "include/" .. name .. "/module.h"}) + --add_rules("engine.plugin", {file = opt and opt.file or "include/" .. name .. "/module.h"}) end function add_dependency(...) add_deps(...) diff --git a/engine/src/engine/api.cpp b/engine/src/engine/api.cpp index 38511ba..66e4137 100644 --- a/engine/src/engine/api.cpp +++ b/engine/src/engine/api.cpp @@ -1,5 +1,6 @@ #include "engine/api.h" #include "os/file_manager.h" +#include "xmalloc_new_delete.h" class ENGINE_API EngineModule : public api::IDynamicModule { public: diff --git a/engine/src/engine/mimalloc.cpp b/engine/src/engine/mimalloc.cpp deleted file mode 100644 index ce655e0..0000000 --- a/engine/src/engine/mimalloc.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "mimalloc-new-delete.h" -//extern void mi_stats_print(void* out); -//extern void mi_collect(bool force); -void clean() { - // 在程序退出时输出内存泄漏信息 - //mi_print_stats(); - // 强制垃圾回收并检查未释放的内存 - mi_stats_print(NULL); - mi_collect(true); -} -struct mi_exit_wrap { - mi_exit_wrap() { - std::atexit(clean); - } -}; -static mi_exit_wrap _mi_exit_wrap; \ No newline at end of file diff --git a/engine/xmake.lua b/engine/xmake.lua index 7735b25..e817938 100644 --- a/engine/xmake.lua +++ b/engine/xmake.lua @@ -12,7 +12,7 @@ target("engine") set_group("Engine") add_rules("engine.api") add_files("src/engine/*.cpp") - add_packages("mimalloc") + add_deps("xmalloc", {public = true}) includes("xmake/xmake.lua") includes("3rdparty/xmake.lua") includes("tools/xmake.lua") diff --git a/game/zworld/editor/zworld_editor.cpp b/game/zworld/editor/zworld_editor.cpp index 6cb17cb..18ea7e9 100644 --- a/game/zworld/editor/zworld_editor.cpp +++ b/game/zworld/editor/zworld_editor.cpp @@ -1,3 +1,6 @@ +#define ZLIB_API +#define ZLIB_API_VAL +#include "xmalloc_new_delete.h" #include "archive/pch.h" #include "test_refl.h" using namespace api; @@ -7,7 +10,7 @@ int main() { { using T = Guid; T a(1,1.0); - + auto ppp = new int(120); T* c = new T(); a.view = "hello"; auto text = TextSerialize(a); diff --git a/game/zworld/src/main.cpp b/game/zworld/src/main.cpp index 5b78d7b..c633838 100644 --- a/game/zworld/src/main.cpp +++ b/game/zworld/src/main.cpp @@ -1,3 +1,4 @@ +#include "xmalloc_new_delete.h" #include "SDL.h" #include "engine/api.h" #include "zlog.h" diff --git a/game/zworld/xmake.lua b/game/zworld/xmake.lua index e30eee1..c4423cc 100644 --- a/game/zworld/xmake.lua +++ b/game/zworld/xmake.lua @@ -9,4 +9,4 @@ target("zworld-editor") }) add_files("editor/*.cpp") add_headerfiles("editor/*.h") - add_deps("zlib", "core", "engine") \ No newline at end of file + add_deps("zlib", "core", "xmalloc") \ No newline at end of file