Files
2026-08-29 00:53:40 +08:00

411 lines
13 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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