#include #if C_IS_OS_WINDOWS #include /* Windows 下的 _aligned_malloc 需要此头文件 */ #endif #ifndef NDEBUG #include #endif /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #if defined(C_MEMORY_USE_LOCAL_SYSTEM) void* c_Memory_Alloc(c_size_t nBytes, const char* file, int line) { return malloc(nBytes); } void* c_Memory_Calloc(c_size_t nCount, c_size_t nBytes, const char* file, int line) { return calloc(nCount, nBytes); } void* c_Memory_Realloc(void* ptr, c_size_t nBytes, const char* file, int line) { return realloc(ptr, nBytes); } void c_Memory_Free(void* ptr, const char* file, int line) { if (!ptr) return; free(ptr); } void* c_Memory_Aligned_Alloc(c_size_t alignment, c_size_t nBytes, const char* file, int line) { /* 1. 统一防御边界:凡是申请 0 字节的,全生命周期内统一斩断并返回 NULL */ if (C_UNLIKELY(nBytes == 0)) { return NULL; } /* 2. 硬件级严苛校验:对齐边界必须大于零,且必须是 2 的有限幂 (如 8, 16, 32, 64) 利用经典的位运算 (align & (align - 1)) == 0 进行快速断言 */ if (C_UNLIKELY(alignment == 0 || (alignment & (alignment - 1)) != 0)) { return NULL; } /* 3. 系统级约束规避:对齐边界绝对不能小于当前平台的指针位宽 (32位系统下为4,64位系统下为8) */ if (alignment < sizeof(void*)) { alignment = sizeof(void*); } void* raw_ptr = NULL; /* ============================================================================== * 🚀 跨平台多路物理分支隔离分化 * ============================================================================== */ #if C_IS_OS_WINDOWS /* 无论您本地使用的是 MSVC 还是 MSYS2 MinGW,在 Windows 上均走微软的原生高速对齐堆接口 */ raw_ptr = _aligned_malloc(nBytes, alignment); #elif C_IS_OS_LINUX || C_IS_OS_FREEBSD || C_IS_OS_MACOS /* 在标准的类 Unix (POSIX) 谱系下,调用 posix_memalign 注意:它的设计是传入指针的指针,成功时返回 0,失败时返回错误码 */ int result = posix_memalign(&raw_ptr, alignment, nBytes); if (C_UNLIKELY(result != 0)) { raw_ptr = NULL; /* 强制拦截,确保失败时指针处于绝对纯净的 NULL 状态 */ } #else /* 终极未知平台兜底:普通的 malloc 在 64 位系统下天然具备 16 字节对齐能力,但无法支持更高对齐 */ /* 如果项目未来被移植到某些不支持 posix_memalign 的极端微内核或嵌入式系统,将在此激活降级 */ raw_ptr = malloc(nBytes); #endif return raw_ptr; } void* c_Memory_Aligned_Calloc(c_size_t alignment, c_size_t num, c_size_t size, const char* file, int line) { c_size_t total_bytes = num * size; if (total_bytes == 0) return NULL; // 直接复用我们写好的跨平台对齐分配器 void* ptr = c_Memory_Aligned_Alloc(alignment, total_bytes, file, line); if (C_LIKELY(ptr)) { // 强制物理内存清零,保证安全性 memset(ptr, 0, total_bytes); } return ptr; } void* c_Memory_Aligned_Realloc(size_t alignment, void* ptr, size_t new_size, const char* file, int line) { if (!ptr) return c_Memory_Aligned_Alloc(alignment, new_size, file, line); if (new_size == 0) { c_Memory_Aligned_Free(ptr, file, line); return NULL; } if (alignment < sizeof(void*)) alignment = sizeof(void*); void* new_ptr = NULL; #if C_IS_OS_WINDOWS new_ptr = _aligned_realloc(ptr, new_size, alignment); #else new_ptr = c_Memory_Aligned_Alloc(alignment, new_size, file, line); if (C_LIKELY(new_ptr)) { memcpy(new_ptr, ptr, new_size); c_Memory_Aligned_Free(ptr, file, line); } #endif return new_ptr; } void c_Memory_Aligned_Free(void* ptr, const char* file, int line) { #if C_IS_OS_WINDOWS /* 🚨 微软大坑警告:Windows 下通过 _aligned_malloc 出来的内存, 必须、绝对、强制使用对应的 _aligned_free 释放!混用普通 free 会直接引发蓝屏或堆破坏崩溃 */ _aligned_free(ptr); #else /* 在 POSIX (Linux, macOS, FreeBSD) 下,posix_memalign 出来的地址本质上只是常规堆的延伸, 可以直接且必须使用标准的 free() 进行释放 */ free(ptr); #endif } #else #if !defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE) C_PACKED_STRUCT_START typedef struct c_MemoryNode_t { void* address; size_t size; const char* file; int line; struct c_MemoryNode_t* next; } C_PACKED c_MemoryNode_t; C_PACKED_STRUCT_END static c_MemoryNode_t* g_tracker_head = NULL; static size_t g_active_allocations = 0; static size_t g_total_allocated_bytes = 0; C_STATIC_FORCE_INLINE int c_tracker_exists(void* ptr) { c_MemoryNode_t* curr = g_tracker_head; while (curr) { if (curr->address == ptr) return 1; curr = curr->next; } return 0; } /* 内部辅助:将分配记录加入追踪器 */ C_STATIC_FORCE_INLINE void c_tracker_add(void* ptr, size_t size, const char* file, int line) { if (!ptr) return; c_MemoryNode_t* node = (c_MemoryNode_t*)malloc(sizeof(c_MemoryNode_t)); if (C_UNLIKELY(!node)) return; /* 防御极端内存耗尽 */ node->address = ptr; node->size = size; node->file = file; node->line = line; node->next = g_tracker_head; g_tracker_head = node; g_active_allocations++; g_total_allocated_bytes += size; } /* 内部辅助:从追踪器中移除释放的记录 */ C_STATIC_FORCE_INLINE void c_tracker_remove(void* ptr) { if (!ptr) return; c_MemoryNode_t* curr = g_tracker_head; c_MemoryNode_t* prev = NULL; while (curr) { if (curr->address == ptr) { if (prev) { prev->next = curr->next; } else { g_tracker_head = curr->next; } g_total_allocated_bytes -= curr->size; g_active_allocations--; free(curr); return; } prev = curr; curr = curr->next; } } /* 内部辅助:根据旧指针反查其原始分配大小(用于 POSIX 链下手动迁移数据) */ C_STATIC_FORCE_INLINE c_size_t c_tracker_get_size(void* ptr) { c_MemoryNode_t* curr = g_tracker_head; while (curr) { if (curr->address == ptr) return curr->size; curr = curr->next; } return 0; } C_STATIC_FORCE_INLINE void c_tracker_update(void* old_ptr, void* new_ptr, size_t new_size, const char* file, int line) { if (!old_ptr) { c_tracker_add(new_ptr, new_size, file, line); return; } c_MemoryNode_t* curr = g_tracker_head; while (curr) { if (curr->address == old_ptr) { // 先扣除旧的全局字节计数,加上新的 g_total_allocated_bytes -= curr->size; g_total_allocated_bytes += new_size; // 更新节点内部物理信息 curr->address = new_ptr; curr->size = new_size; curr->file = file; curr->line = line; return; } curr = curr->next; } /* 防御边界:如果追踪器里没找到旧指针(例如用户混用了外部指针),则强制当作新指针加入 */ c_tracker_add(new_ptr, new_size, file, line); } #endif /* ------------------------------------------------------------------------------------------------------------------ */ /* */ void* c_Memory_Aligned_Alloc(c_size_t alignment, c_size_t size, const char* file, int line) { if (size == 0) return NULL; void* raw_ptr = NULL; /* 确保对齐边界合法(必须是2的幂且大于指针大小) */ if (alignment < sizeof(void*)) alignment = sizeof(void*); #if C_IS_OS_WINDOWS /* 无论是 MSVC 还是您的 MSYS2 MinGW,在 Windows 上均调用此原生安全接口 */ raw_ptr = _aligned_malloc(size, alignment); #elif C_IS_OS_MACOS /* macOS 原生 malloc 在满足边界时已经高度对齐,或者使用 posix_memalign */ if (posix_memalign(&raw_ptr, alignment, size) != 0) { raw_ptr = NULL; } #elif C_IS_OS_LINUX || C_IS_OS_FREEBSD /* Linux 和 FreeBSD 的标准 POSIX 对齐接口 */ if (posix_memalign(&raw_ptr, alignment, size) != 0) { raw_ptr = NULL; } #else /* 终极兜底降级方案:常规分配(不对齐) */ raw_ptr = malloc(size); #endif #if !defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE) /* 注入追踪器 */ if (C_LIKELY(raw_ptr)) { c_tracker_add(raw_ptr, size, file, line); } #endif return raw_ptr; } void c_Memory_Aligned_Free(void* ptr, const char* file, int line) { if (!ptr) return; C_UNUSED(file); C_UNUSED(line); #if !defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE) /* 从日志中移除 */ c_tracker_remove(ptr); #endif #if C_IS_OS_WINDOWS _aligned_free(ptr); /* Windows 的对齐内存必须用配套的 free 释放 */ #else free(ptr); /* POSIX (Linux/Mac/FreeBSD) 的 posix_memalign 直接用常规 free 即可 */ #endif } void* c_Memory_Aligned_Calloc(c_size_t alignment, c_size_t num, c_size_t size, const char* file, int line) { c_size_t total_bytes = num * size; if (total_bytes == 0) return NULL; // 直接复用我们写好的跨平台对齐分配器 void* ptr = c_Memory_Aligned_Alloc(alignment, total_bytes, file, line); if (C_LIKELY(ptr)) { // 强制物理内存清零,保证安全性 memset(ptr, 0, total_bytes); } return ptr; } void* c_Memory_Aligned_Realloc(size_t alignment, void* ptr, size_t new_size, const char* file, int line) { #if !(!defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE)) && defined(C_MEMORY_CHECK_ENABLE) /* Debug 模式下的野指针前置拦截 */ if (ptr != NULL) { if (C_UNLIKELY(!c_tracker_exists(ptr))) { fprintf(stderr, "🚨 [CRITICAL ERROR] %s:%d 试图用未知野指针调用 Aligned_Realloc: %p!\n", file, line, ptr); assert(0 && "c_Memory_Aligned_Realloc Fail: Wild pointer!"); } } #endif if (!ptr) return c_Memory_Aligned_Alloc(alignment, new_size, file, line); if (new_size == 0) { c_Memory_Aligned_Free(ptr, file, line); return NULL; } if (alignment < sizeof(void*)) alignment = sizeof(void*); void* new_ptr = NULL; #if !(!defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE)) && !C_IS_OS_WINDOWS /* Debug 模式下非 Windows 系统的“严格毒化迁移” */ c_size_t old_size = c_tracker_get_size(ptr); new_ptr = c_Memory_Aligned_Alloc(alignment, new_size, file, line); if (C_LIKELY(new_ptr)) { c_size_t copy_size = (old_size < new_size) ? old_size : new_size; if (copy_size > 0) memcpy(new_ptr, ptr, copy_size); memset(ptr, 0xDD, old_size); /* 毒化 */ c_Memory_Aligned_Free(ptr, file, line); c_tracker_update(NULL, new_ptr, new_size, file, line); } #else /* Release 生产环境或 Windows 环境下的原生高性能逻辑 */ #if C_IS_OS_WINDOWS new_ptr = _aligned_realloc(ptr, new_size, alignment); #else new_ptr = c_Memory_Aligned_Alloc(alignment, new_size, file, line); if (C_LIKELY(new_ptr)) { memcpy(new_ptr, ptr, new_size); c_Memory_Aligned_Free(ptr, file, line); } #endif #if !defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE) if (C_LIKELY(new_ptr)) { c_tracker_update(ptr, new_ptr, new_size, file, line); } #endif #endif #if !defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE) if (C_UNLIKELY(!new_ptr)) { fprintf(stderr, "🚨 [OOM CRITICAL] %s:%d 内存耗尽,无法重分配 %lu 字节!\n", file, line, (unsigned long)new_size); assert(0 && "Out of Memory!"); } #endif return new_ptr; } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ void* c_Memory_Alloc(c_size_t nBytes, const char* file, int line) { return c_Memory_Aligned_Alloc(C_ALIGN_SIZE, nBytes, file, line); } void* c_Memory_Calloc(c_size_t nCount, c_size_t nBytes, const char* file, int line) { return c_Memory_Aligned_Calloc(C_ALIGN_SIZE, nCount, nBytes, file, line); } void* c_Memory_Realloc(void* ptr, c_size_t nBytes, const char* file, int line) { return c_Memory_Aligned_Realloc(C_ALIGN_SIZE, ptr, nBytes, file, line); } void c_Memory_Free(void* ptr, const char* file, int line) { c_Memory_Aligned_Free(ptr, file, line); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ #if !defined(NDEBUG) && defined(C_MEMORY_CHECK_ENABLE) c_size_t c_memory_leak_report(void) { if (g_active_allocations == 0) { return 0; } printf("\n🚨 [MEMORY AUDIT] 检测到内存泄漏! 未释放的泄漏列表如下:\n"); c_MemoryNode_t* curr = g_tracker_head; while (curr) { printf(" -> 泄漏地址: %p | 大小: %lu 字节 | 位置: %s (第 %d 行)\n", curr->address, (unsigned long)curr->size, curr->file, curr->line); curr = curr->next; } return g_total_allocated_bytes; } void c_memory_tracker_reset(void) { c_MemoryNode_t* curr = g_tracker_head; while (curr) { c_MemoryNode_t* next = curr->next; free(curr); curr = next; } g_tracker_head = NULL; g_active_allocations = 0; g_total_allocated_bytes = 0; } #endif #endif