diff --git a/include/HMem.h b/include/HMem.h new file mode 100644 index 0000000..97921aa --- /dev/null +++ b/include/HMem.h @@ -0,0 +1,101 @@ +/** + * 日期: 2026-03-31 + * 作者: coffee + * 描述: 基于 HTlsf 的引用计数内存管理模块 + * 单例模式,只需初始化一次 + * 支持引用计数、自动释放、外部内存拷贝转换 + */ + +#ifndef _H_MEM_H_ +#define _H_MEM_H_ + + +#include +#include + + +/** + * @brief 初始化内存管理器(单例模式,只需调用一次) + * @param buffer 外部缓冲区 + * @param size 缓冲区大小 + * @return 成功返回1, 失败返回0 + */ +uint8_t HMemInit(void *buffer, size_t size); + +/** + * @brief 判断是否已初始化 + */ +uint8_t HMemIsReady(void); + +/** + * @brief 分配内存 + * @param size 请求大小 + * @return 成功返回内存指针, 失败返回NULL + */ +void *HMemMalloc(size_t size); + +/** + * @brief 分配并清零内存 + * @param num 元素数量 + * @param size 每个元素大小 + * @return 成功返回内存指针, 失败返回NULL + */ +void *HMemCalloc(size_t num, size_t size); + +/** + * @brief 重新分配内存 + * @param ptr 原内存指针 + * @param size 新大小 + * @return 成功返回内存指针, 失败返回NULL (原内存保持不变) + */ +void *HMemRealloc(void *ptr, size_t size); + +/** + * @brief 释放内存 (引用计数为0时才真正释放) + * @param ptr 内存指针 + * @return 成功返回1, 失败返回0 + */ +uint8_t HMemFree(void *ptr); + +/** + * @brief 增加引用计数或拷贝外部内存 + * @param ptr 内存指针 (可以是外部内存) + * @param size 如果是外部内存,指定要拷贝的大小;如果是 HMem 内存,此参数被忽略 + * @return + * - 如果是 HMem 分配的内存, 返回 ptr (引用计数+1) + * - 如果是外部内存, 返回新分配的内存指针 (内容已拷贝) + * - 内存不足返回 NULL + */ +void *HMemAddRef(void *ptr, size_t size); + +/** + * @brief 获取当前引用计数 + * @param ptr 内存指针 + * @return 引用计数, 如果不是 HMem 分配的返回 0 + */ +uint32_t HMemGetRefCount(void *ptr); + +/** + * @brief 判断指针是否由 HMem 分配 + * @param ptr 内存指针 + * @return 是返回1, 否返回0 + */ +uint8_t HMemIsManaged(void *ptr); + +/** + * @brief 获取可用内存大小 + */ +size_t HMemGetFreeSize(void); + +/** + * @brief 获取已使用内存大小 + */ +size_t HMemGetUsedSize(void); + +/** + * @brief 获取总容量 + */ +size_t HMemGetCapacity(void); + + +#endif // _H_MEM_H_ diff --git a/include/HTlsf.h b/include/HTlsf.h index f56e53e..9e46eca 100644 --- a/include/HTlsf.h +++ b/include/HTlsf.h @@ -54,6 +54,14 @@ size_t HTlsfPoolOverhead(void); */ size_t HTlsfMinBufferSize(void); +/** + * @brief 初始化所需的最大原始内存大小 + * + * 说明: + * 返回值已包含最坏情况下的对齐填充 + */ +size_t HTlsfMaxBufferSize(void); + /** * @brief 初始化 TLSF 内存池 * @param htlsf 上下文 diff --git a/src/HMem.c b/src/HMem.c new file mode 100644 index 0000000..915925a --- /dev/null +++ b/src/HMem.c @@ -0,0 +1,303 @@ +/** + * 日期: 2026-03-31 + * 作者: coffee + * 描述: 基于 HTlsf 的引用计数内存管理模块实现 + * 优化版:头部仅4字节,使用位域结构 + */ + +#include "HMem.h" +#include "HTlsf.h" +#include + +#ifndef LogD +#define LogD(...) +#endif + +/* + * 头部布局 (4字节): + * - userSize: 16 bits, 用户请求大小 (最大 65535 字节) + * - magic: 10 bits, 魔数 (0x2AA = 0b1010101010) + * - refCount: 6 bits, 引用计数 (最大 63) + */ + +#define HMEM_MAGIC_VALUE 0x2AAu +#define HMEM_REFCOUNT_MAX 63u +#define HMEM_SIZE_MAX 65535u + +typedef struct __attribute__((packed)) HMemHeader { + uint16_t userSize; /* 用户请求大小 */ + uint16_t refCount :6; /* 引用计数 */ + uint16_t magic :10; /* 魔数 */ +} HMemHeader; + +#define HMEM_HEADER_SIZE sizeof(HMemHeader) + +/* 编译期确保头部大小为4字节 */ +typedef char HMemHeaderSizeCheck[HMEM_HEADER_SIZE == 4 ? 1 : -1]; + +/* 对齐辅助 */ +#define HMEM_ALIGN_SIZE sizeof(void*) +#define HMEM_ALIGN_UP(x) (((x) + HMEM_ALIGN_SIZE - 1) & ~(HMEM_ALIGN_SIZE - 1)) +#define HMEM_USER_OFFSET HMEM_ALIGN_UP(HMEM_HEADER_SIZE) + +/* 全局单例 */ +static HTlsf sTlsf; + +static uint8_t PtrMayBeInPool(const void *ptr) { + if (!HTlsfIsReady(&sTlsf) || ptr == NULL) { + return 0; + } + + uintptr_t poolStart = (uintptr_t)sTlsf.mem; + uintptr_t poolEnd = poolStart + sTlsf.memSize; + uintptr_t userPtr = (uintptr_t)ptr; + + return userPtr >= (poolStart + HMEM_USER_OFFSET) && userPtr < poolEnd; +} + +static HMemHeader *GetHeader(const void *ptr) { + if (ptr == NULL) { + return NULL; + } + + if (!PtrMayBeInPool(ptr)) { + return NULL; + } + + return (HMemHeader *)((uint8_t *)ptr - HMEM_USER_OFFSET); +} + +static void *GetUserPtr(HMemHeader *header) { + if (header == NULL) { + return NULL; + } + return (void *)((uint8_t *)header + HMEM_USER_OFFSET); +} + +static uint8_t IsValidHeader(const HMemHeader *header) { + if (header == NULL) { + return 0; + } + return header->magic == HMEM_MAGIC_VALUE; +} + +static uint8_t IsReady(void) { + return HTlsfIsReady(&sTlsf); +} + +uint8_t HMemInit(void *buffer, size_t size) { + if (buffer == NULL || size == 0) { + return 0; + } + + if (size > HTlsfMaxBufferSize()) { + size = HTlsfMaxBufferSize(); + } + + if (HTlsfInit(&sTlsf, buffer, size)) { + return 1; + } + + return 0; +} + +uint8_t HMemIsReady(void) { + return IsReady(); +} + +void *HMemMalloc(size_t size) { + if (!IsReady() || size == 0 || size > HMEM_SIZE_MAX) { + return NULL; + } + + /* 分配时加上头部空间 */ + size_t totalSize = HMEM_USER_OFFSET + size; + void *raw = HTlsfMalloc(&sTlsf, totalSize); + if (raw == NULL) { + return NULL; + } + + /* 初始化头部 */ + HMemHeader *header = (HMemHeader *)raw; + header->magic = HMEM_MAGIC_VALUE; + header->refCount = 1; + header->userSize = (uint16_t)size; + + return GetUserPtr(header); +} + +void *HMemCalloc(size_t num, size_t size) { + if (!IsReady() || num == 0 || size == 0) { + return NULL; + } + + if (num > (SIZE_MAX / size)) { + return NULL; + } + + size_t total = num * size; + void *ptr = HMemMalloc(total); + if (ptr != NULL) { + memset(ptr, 0, total); + } + + return ptr; +} + +void *HMemRealloc(void *ptr, size_t size) { + if (!IsReady()) { + return NULL; + } + + if (size > HMEM_SIZE_MAX) { + return NULL; + } + + /* ptr == NULL 等价于 malloc */ + if (ptr == NULL) { + return HMemMalloc(size); + } + + /* size == 0 等价于 free */ + if (size == 0) { + HMemFree(ptr); + return NULL; + } + + HMemHeader *header = GetHeader(ptr); + if (!IsValidHeader(header)) { + return NULL; + } + + size_t oldSize = header->userSize; + + /* 如果新大小相同,直接返回 */ + if (size == oldSize) { + return ptr; + } + + if (header->refCount == 1u) { + size_t totalSize = HMEM_USER_OFFSET + size; + void *raw = HTlsfRealloc(&sTlsf, header, totalSize); + if (raw == NULL) { + return NULL; + } + + header = (HMemHeader *)raw; + header->magic = HMEM_MAGIC_VALUE; + header->refCount = 1u; + header->userSize = (uint16_t)size; + return GetUserPtr(header); + } + + /* 分配新内存 */ + void *newPtr = HMemMalloc(size); + if (newPtr == NULL) { + return NULL; + } + + /* 拷贝数据 */ + size_t copySize = (oldSize < size) ? oldSize : size; + memcpy(newPtr, ptr, copySize); + + /* 释放旧内存 */ + HMemFree(ptr); + + return newPtr; +} + +uint8_t HMemFree(void *ptr) { + if (!IsReady() || ptr == NULL) { + return 0; + } + + HMemHeader *header = GetHeader(ptr); + if (!IsValidHeader(header)) { + return 0; + } + + /* 引用计数减一 */ + if (header->refCount > 0) { + --header->refCount; + } + + /* 引用计数为0时才真正释放 */ + if (header->refCount == 0) { + header->magic = 0; /* 清除魔数,防止再次释放 */ + HTlsfFree(&sTlsf, header); + } + + return 1; +} + +void *HMemAddRef(void *ptr, size_t size) { + if (!IsReady() || ptr == NULL) { + return NULL; + } + + HMemHeader *header = GetHeader(ptr); + + /* 如果是 HMem 分配的内存 */ + if (IsValidHeader(header)) { + if (header->refCount < HMEM_REFCOUNT_MAX) { + ++header->refCount; + } + return ptr; + } + + /* 不是 HMem 分配的内存,需要拷贝到新内存 */ + if (size == 0) { + return NULL; + } + + void *newPtr = HMemMalloc(size); + if (newPtr == NULL) { + return NULL; + } + + memcpy(newPtr, ptr, size); + return newPtr; +} + +uint32_t HMemGetRefCount(void *ptr) { + if (ptr == NULL) { + return 0; + } + + HMemHeader *header = GetHeader(ptr); + if (!IsValidHeader(header)) { + return 0; + } + + return header->refCount; +} + +uint8_t HMemIsManaged(void *ptr) { + if (ptr == NULL) { + return 0; + } + + HMemHeader *header = GetHeader(ptr); + return IsValidHeader(header); +} + +size_t HMemGetFreeSize(void) { + if (!IsReady()) { + return 0; + } + return HTlsfGetFreeSize(&sTlsf); +} + +size_t HMemGetUsedSize(void) { + if (!IsReady()) { + return 0; + } + return HTlsfGetUsedSize(&sTlsf); +} + +size_t HMemGetCapacity(void) { + if (!IsReady()) { + return 0; + } + return HTlsfGetCapacity(&sTlsf); +} diff --git a/src/HTlsf.c b/src/HTlsf.c index 2ba679f..2f24d17 100644 --- a/src/HTlsf.c +++ b/src/HTlsf.c @@ -1144,6 +1144,11 @@ size_t HTlsfMinBufferSize(void) return HTlsfControlSize() + sPoolOverhead + sBlockSizeMin + kHTlsfAlignSize - 1; } +size_t HTlsfMaxBufferSize(void) +{ + return sBlockSizeMax; +} + uint8_t HTlsfInit(HTlsf *htlsf, void *mem, size_t size) { uintptr_t raw;