411 lines
13 KiB
C
411 lines
13 KiB
C
#include <c_Memory.h>
|
||
|
||
#if C_IS_OS_WINDOWS
|
||
#include <malloc.h> /* Windows 下的 _aligned_malloc 需要此头文件 */
|
||
#endif
|
||
|
||
#ifndef NDEBUG
|
||
#include <stdio.h>
|
||
#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
|