mirror of
https://gitee.com/apaki/unicstl.git
synced 2026-05-28 22:54:19 +08:00
feat(mempool)!: 添加内存追踪及修复多处内存泄漏
- 新增 mempool 模块用于统计内存分配次数并检测泄漏 - 启用 UNICSTL_MALLOC_CUSTOM 宏以接管标准库内存函数 - 修复 segarray 销毁时未释放 _mapfree 导致的内存泄漏 - 修复 darray 迭代器 next 方法中错误的对象访问方式 - 调整 segarray 不支持外部缓存 - 修复测试用例中未释放 arraylist 导致的误报
This commit is contained in:
parent
529cf60218
commit
82d0167c81
26
include/mempool.h
Normal file
26
include/mempool.h
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file mempool.h
|
||||
* @author wenjf (Orig5826@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2026-05-17
|
||||
*
|
||||
* @copyright Copyright (c) 2026
|
||||
*
|
||||
*/
|
||||
#ifndef _MEMPOOL_H_
|
||||
#define _MEMPOOL_H_
|
||||
|
||||
#include "unicstl_internal.h"
|
||||
|
||||
#ifdef UNICSTL_MALLOC_CUSTOM
|
||||
extern void *unicstl_malloc(size_t size);
|
||||
extern void *unicstl_calloc(size_t num, size_t size);
|
||||
extern void *unicstl_realloc(void *ptr, size_t size);
|
||||
extern void unicstl_free(void *ptr);
|
||||
#endif
|
||||
|
||||
void mempool_init(void);
|
||||
void mempool_deinit(void);
|
||||
|
||||
#endif // _MEMPOOL_H_
|
||||
@ -13,6 +13,8 @@
|
||||
|
||||
#include "unicstl_internal.h"
|
||||
|
||||
#include "mempool.h"
|
||||
|
||||
#include "darray.h"
|
||||
#include "linklist.h"
|
||||
#include "dlinklist.h"
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
*
|
||||
*/
|
||||
#define UNICSTL_MALLOC_ENABLE // malloc enable
|
||||
// #define UNICSTL_MALLOC_CUSTOM // malloc custom support
|
||||
#define UNICSTL_MALLOC_CUSTOM // malloc custom support
|
||||
|
||||
|
||||
/**
|
||||
|
||||
2
mk.bat
2
mk.bat
@ -1,6 +1,8 @@
|
||||
@REM D:\Lang\cmake-3.27.5-windows-x86_64\bin\cmake.EXE --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=D:\Software\mingw64\bin\gcc.exe -DCMAKE_CXX_COMPILER:FILEPATH=D:\Software\mingw64\bin\g++.exe -SF:/OpenDemo/1_vsc_cmake -Bf:/OpenDemo/1_vsc_cmake/build -G "MinGW Makefiles"
|
||||
@REM cmake -Bbuild -G "Visual Studio 17 2022"
|
||||
|
||||
del ".\build\release\bin\test.exe"
|
||||
|
||||
cmake -B build -G "MinGW Makefiles"
|
||||
@REM cmake -B build -G "Unix Makefiles"
|
||||
|
||||
|
||||
@ -221,10 +221,7 @@ const void *darray_iter_next(struct _iterator *iter)
|
||||
{
|
||||
iter->_index = iter->_index - 1;
|
||||
}
|
||||
return obj_at(self->obj, index, self->_obj_size);
|
||||
|
||||
// log_debug("index:%zu", index);
|
||||
// return self->at(self->obj, index); // TODO: 这里有问题,结构体指针都崩了
|
||||
return self->at(self, index);
|
||||
}
|
||||
|
||||
iterator_t darray_iter(struct _darray *self, linear_order_t order)
|
||||
|
||||
90
src/mempool.c
Normal file
90
src/mempool.c
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file mempool.c
|
||||
* @author wenjf (Orig5826@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2026-05-17
|
||||
*
|
||||
* @copyright Copyright (c) 2026
|
||||
*
|
||||
*/
|
||||
#include "mempool.h"
|
||||
|
||||
#ifdef UNICSTL_MALLOC_CUSTOM
|
||||
|
||||
typedef struct _mempool
|
||||
{
|
||||
size_t count_total;
|
||||
size_t count_free;
|
||||
|
||||
size_t count_malloc;
|
||||
size_t count_calloc;
|
||||
size_t count_realloc;
|
||||
}mempool_t;
|
||||
|
||||
static mempool_t mempool;
|
||||
|
||||
|
||||
void mempool_init()
|
||||
{
|
||||
memset(&mempool, 0, sizeof(mempool_t));
|
||||
}
|
||||
|
||||
void mempool_deinit()
|
||||
{
|
||||
printf("\n------------------------------ \n");
|
||||
printf("count_total: %zu\n", mempool.count_total);
|
||||
printf("count_free: %zu\n", mempool.count_free);
|
||||
printf("count_malloc: %zu\n", mempool.count_malloc);
|
||||
printf("count_calloc: %zu\n", mempool.count_calloc);
|
||||
printf("count_realloc: %zu\n", mempool.count_realloc);
|
||||
|
||||
size_t leak = mempool.count_total - mempool.count_free;
|
||||
if (mempool.count_total > mempool.count_free)
|
||||
{
|
||||
printf("\nERROR: maybe leak: %zu\n", leak);
|
||||
}
|
||||
else if (mempool.count_total < mempool.count_free)
|
||||
{
|
||||
printf("\nERROR: maybe free too many\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\nOK: no leak\n");
|
||||
}
|
||||
memset(&mempool, 0, sizeof(mempool_t));
|
||||
}
|
||||
|
||||
void *unicstl_malloc(size_t size)
|
||||
{
|
||||
mempool.count_malloc++;
|
||||
mempool.count_total++;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *unicstl_calloc(size_t num, size_t size)
|
||||
{
|
||||
mempool.count_calloc++;
|
||||
mempool.count_total++;
|
||||
return calloc(num, size);
|
||||
}
|
||||
|
||||
void *unicstl_realloc(void *ptr, size_t size)
|
||||
{
|
||||
mempool.count_realloc++;
|
||||
if(ptr == NULL)
|
||||
{
|
||||
mempool.count_total++;
|
||||
}
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
void unicstl_free(void *ptr)
|
||||
{
|
||||
if (ptr != NULL)
|
||||
{
|
||||
mempool.count_free++;
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
117
src/segarray.c
117
src/segarray.c
@ -432,22 +432,33 @@ static bool segarray_clear(struct _segarray *self)
|
||||
static void segarray_destory(struct _segarray *self)
|
||||
{
|
||||
unicstl_assert(self != NULL);
|
||||
ringbuf_t map = self->_map;
|
||||
if (self->_dynamic && map != NULL)
|
||||
ringbuf_t map_used[2] = {
|
||||
self->_map,
|
||||
self->_mapfree
|
||||
};
|
||||
|
||||
if(self->_dynamic == true)
|
||||
{
|
||||
rawbuf_t seg = NULL;
|
||||
while(!map->empty(map))
|
||||
|
||||
ringbuf_t map = self->_map;
|
||||
for(size_t i = 0; i < 2; i++)
|
||||
{
|
||||
if (map->pop_back(map, &seg))
|
||||
map = map_used[i];
|
||||
while(!map->empty(map))
|
||||
{
|
||||
if(seg == NULL)
|
||||
if (map->pop_back(map, &seg))
|
||||
{
|
||||
log_error("seg is NULL");
|
||||
if(seg == NULL)
|
||||
{
|
||||
log_error("seg is NULL");
|
||||
}
|
||||
rawbuf_free(&seg);
|
||||
}
|
||||
rawbuf_free(&seg);
|
||||
}
|
||||
}
|
||||
ringbuf_free(&self->_map);
|
||||
ringbuf_free(&self->_mapfree);
|
||||
}
|
||||
log_debug("segarray destoryed!");
|
||||
}
|
||||
@ -540,11 +551,10 @@ iterator_t segarray_iter(struct _segarray *self, linear_order_t order)
|
||||
* @param self
|
||||
* @param obj_size
|
||||
* @param capacity
|
||||
* @param mem_pool !!! mem_pool_size = capacity * obj_size
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool segarray_init(struct _segarray *self, size_t obj_size, size_t capacity, void *mem_pool)
|
||||
static bool segarray_init(struct _segarray *self, size_t obj_size, size_t capacity)
|
||||
{
|
||||
unicstl_assert(self != NULL);
|
||||
unicstl_assert(obj_size > 0);
|
||||
@ -555,53 +565,6 @@ bool segarray_init(struct _segarray *self, size_t obj_size, size_t capacity, voi
|
||||
self->_capacity = capacity;
|
||||
self->_segsize = capacity;
|
||||
|
||||
if (mem_pool != NULL)
|
||||
{
|
||||
self->obj = (char *)mem_pool;
|
||||
self->_dynamic = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->_dynamic = true;
|
||||
|
||||
self->_map = ringbuf_new(sizeof(rawbuf_t), 8);
|
||||
if (self->_map == NULL)
|
||||
{
|
||||
log_warn("self->_map new failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
self->_mapfree = ringbuf_new(sizeof(rawbuf_t), 8);
|
||||
if (self->_mapfree == NULL)
|
||||
{
|
||||
log_warn("self->_mapfree new failed!");
|
||||
ringbuf_free(&self->_map);
|
||||
return false;
|
||||
}
|
||||
|
||||
rawbuf_t seg = rawbuf_new(obj_size, self->_segsize);
|
||||
if (seg == NULL)
|
||||
{
|
||||
log_warn("seg new failed!");
|
||||
ringbuf_free(&self->_map);
|
||||
ringbuf_free(&self->_mapfree);
|
||||
return false;
|
||||
}
|
||||
// config first obj index in seg array
|
||||
self->_seghead = clac_start_index(self->_segsize);
|
||||
self->_segtail = self->_seghead;
|
||||
|
||||
// add first seg array to map
|
||||
if(!self->_map->push_back(self->_map, &seg))
|
||||
{
|
||||
log_warn("self->_map push back failed!");
|
||||
rawbuf_free(&seg);
|
||||
ringbuf_free(&self->_map);
|
||||
ringbuf_free(&self->_mapfree);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self->_destory = segarray_destory;
|
||||
|
||||
// -------------------- public --------------------
|
||||
@ -635,6 +598,46 @@ bool segarray_init(struct _segarray *self, size_t obj_size, size_t capacity, voi
|
||||
// -------------------- debug --------------------
|
||||
self->print = segarray_print;
|
||||
|
||||
// -------------------- memory --------------------
|
||||
|
||||
self->_dynamic = true;
|
||||
|
||||
self->_map = ringbuf_new(sizeof(rawbuf_t), 8);
|
||||
if (self->_map == NULL)
|
||||
{
|
||||
log_warn("self->_map new failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
self->_mapfree = ringbuf_new(sizeof(rawbuf_t), 8);
|
||||
if (self->_mapfree == NULL)
|
||||
{
|
||||
log_warn("self->_mapfree new failed!");
|
||||
ringbuf_free(&self->_map);
|
||||
return false;
|
||||
}
|
||||
|
||||
rawbuf_t seg = rawbuf_new(obj_size, self->_segsize);
|
||||
if (seg == NULL)
|
||||
{
|
||||
log_warn("seg new failed!");
|
||||
ringbuf_free(&self->_map);
|
||||
ringbuf_free(&self->_mapfree);
|
||||
return false;
|
||||
}
|
||||
// config first obj index in seg array
|
||||
self->_seghead = clac_start_index(self->_segsize);
|
||||
self->_segtail = self->_seghead;
|
||||
|
||||
// add first seg array to map
|
||||
if(!self->_map->push_back(self->_map, &seg))
|
||||
{
|
||||
log_warn("self->_map push back failed!");
|
||||
rawbuf_free(&seg);
|
||||
ringbuf_free(&self->_map);
|
||||
ringbuf_free(&self->_mapfree);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -648,7 +651,7 @@ segarray_t segarray_new(size_t obj_size, size_t capacity)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (segarray_init(segarray, obj_size, capacity, NULL) != true)
|
||||
if (segarray_init(segarray, obj_size, capacity) != true)
|
||||
{
|
||||
log_warn("segarray init failed");
|
||||
unicstl_free(segarray);
|
||||
|
||||
11
test/test.c
11
test/test.c
@ -75,11 +75,12 @@ void tearDown(void)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
log_init();
|
||||
|
||||
printf("----- Unicstl Unit Test -----\n");
|
||||
UNITY_BEGIN();
|
||||
|
||||
log_init();
|
||||
mempool_init();
|
||||
|
||||
TEST_ADD(test_unicstl);
|
||||
|
||||
TEST_ADD(test_linklist);
|
||||
@ -94,15 +95,15 @@ int main(int argc, char const *argv[])
|
||||
TEST_ADD(test_queue);
|
||||
TEST_ADD(test_stack);
|
||||
|
||||
// TEST_ADD(test_list);
|
||||
// TEST_ADD(test_heap);
|
||||
TEST_ADD(test_list);
|
||||
TEST_ADD(test_heap);
|
||||
// TEST_ADD(test_tree);
|
||||
// TEST_ADD(test_graph);
|
||||
|
||||
TEST_ADD(test_segarray);
|
||||
|
||||
TEST_ADD(test_arraylist);
|
||||
|
||||
mempool_deinit();
|
||||
log_deinit();
|
||||
return UNITY_END();
|
||||
}
|
||||
|
||||
@ -395,6 +395,8 @@ static void test_arraylist_at(void)
|
||||
|
||||
p_int = arraylist->at(arraylist, 9);
|
||||
TEST_ASSERT_EQUAL_INT(10, *p_int);
|
||||
|
||||
arraylist_free(&arraylist);
|
||||
}
|
||||
|
||||
static void test_arraylist_at_negative(void)
|
||||
@ -420,6 +422,8 @@ static void test_arraylist_at_negative(void)
|
||||
|
||||
p_int = arraylist->at(arraylist, -1);
|
||||
TEST_ASSERT_EQUAL_INT(10, *p_int);
|
||||
|
||||
arraylist_free(&arraylist);
|
||||
}
|
||||
|
||||
static void test_arraylist_at_invalid(void)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user