mirror of
https://gitee.com/apaki/unicstl.git
synced 2026-05-29 07:04:20 +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 "unicstl_internal.h"
|
||||||
|
|
||||||
|
#include "mempool.h"
|
||||||
|
|
||||||
#include "darray.h"
|
#include "darray.h"
|
||||||
#include "linklist.h"
|
#include "linklist.h"
|
||||||
#include "dlinklist.h"
|
#include "dlinklist.h"
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define UNICSTL_MALLOC_ENABLE // malloc enable
|
#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 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"
|
@REM cmake -Bbuild -G "Visual Studio 17 2022"
|
||||||
|
|
||||||
|
del ".\build\release\bin\test.exe"
|
||||||
|
|
||||||
cmake -B build -G "MinGW Makefiles"
|
cmake -B build -G "MinGW Makefiles"
|
||||||
@REM cmake -B build -G "Unix 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;
|
iter->_index = iter->_index - 1;
|
||||||
}
|
}
|
||||||
return obj_at(self->obj, index, self->_obj_size);
|
return self->at(self, index);
|
||||||
|
|
||||||
// log_debug("index:%zu", index);
|
|
||||||
// return self->at(self->obj, index); // TODO: 这里有问题,结构体指针都崩了
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator_t darray_iter(struct _darray *self, linear_order_t order)
|
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)
|
static void segarray_destory(struct _segarray *self)
|
||||||
{
|
{
|
||||||
unicstl_assert(self != NULL);
|
unicstl_assert(self != NULL);
|
||||||
ringbuf_t map = self->_map;
|
ringbuf_t map_used[2] = {
|
||||||
if (self->_dynamic && map != NULL)
|
self->_map,
|
||||||
|
self->_mapfree
|
||||||
|
};
|
||||||
|
|
||||||
|
if(self->_dynamic == true)
|
||||||
{
|
{
|
||||||
rawbuf_t seg = NULL;
|
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->_map);
|
||||||
|
ringbuf_free(&self->_mapfree);
|
||||||
}
|
}
|
||||||
log_debug("segarray destoryed!");
|
log_debug("segarray destoryed!");
|
||||||
}
|
}
|
||||||
@ -540,11 +551,10 @@ iterator_t segarray_iter(struct _segarray *self, linear_order_t order)
|
|||||||
* @param self
|
* @param self
|
||||||
* @param obj_size
|
* @param obj_size
|
||||||
* @param capacity
|
* @param capacity
|
||||||
* @param mem_pool !!! mem_pool_size = capacity * obj_size
|
|
||||||
* @return true
|
* @return true
|
||||||
* @return false
|
* @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(self != NULL);
|
||||||
unicstl_assert(obj_size > 0);
|
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->_capacity = capacity;
|
||||||
self->_segsize = 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;
|
self->_destory = segarray_destory;
|
||||||
|
|
||||||
// -------------------- public --------------------
|
// -------------------- public --------------------
|
||||||
@ -635,6 +598,46 @@ bool segarray_init(struct _segarray *self, size_t obj_size, size_t capacity, voi
|
|||||||
// -------------------- debug --------------------
|
// -------------------- debug --------------------
|
||||||
self->print = segarray_print;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +651,7 @@ segarray_t segarray_new(size_t obj_size, size_t capacity)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segarray_init(segarray, obj_size, capacity, NULL) != true)
|
if (segarray_init(segarray, obj_size, capacity) != true)
|
||||||
{
|
{
|
||||||
log_warn("segarray init failed");
|
log_warn("segarray init failed");
|
||||||
unicstl_free(segarray);
|
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[])
|
int main(int argc, char const *argv[])
|
||||||
{
|
{
|
||||||
log_init();
|
|
||||||
|
|
||||||
printf("----- Unicstl Unit Test -----\n");
|
printf("----- Unicstl Unit Test -----\n");
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
|
|
||||||
|
log_init();
|
||||||
|
mempool_init();
|
||||||
|
|
||||||
TEST_ADD(test_unicstl);
|
TEST_ADD(test_unicstl);
|
||||||
|
|
||||||
TEST_ADD(test_linklist);
|
TEST_ADD(test_linklist);
|
||||||
@ -94,15 +95,15 @@ int main(int argc, char const *argv[])
|
|||||||
TEST_ADD(test_queue);
|
TEST_ADD(test_queue);
|
||||||
TEST_ADD(test_stack);
|
TEST_ADD(test_stack);
|
||||||
|
|
||||||
// TEST_ADD(test_list);
|
TEST_ADD(test_list);
|
||||||
// TEST_ADD(test_heap);
|
TEST_ADD(test_heap);
|
||||||
// TEST_ADD(test_tree);
|
// TEST_ADD(test_tree);
|
||||||
// TEST_ADD(test_graph);
|
// TEST_ADD(test_graph);
|
||||||
|
|
||||||
TEST_ADD(test_segarray);
|
TEST_ADD(test_segarray);
|
||||||
|
|
||||||
TEST_ADD(test_arraylist);
|
TEST_ADD(test_arraylist);
|
||||||
|
|
||||||
|
mempool_deinit();
|
||||||
log_deinit();
|
log_deinit();
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -395,6 +395,8 @@ static void test_arraylist_at(void)
|
|||||||
|
|
||||||
p_int = arraylist->at(arraylist, 9);
|
p_int = arraylist->at(arraylist, 9);
|
||||||
TEST_ASSERT_EQUAL_INT(10, *p_int);
|
TEST_ASSERT_EQUAL_INT(10, *p_int);
|
||||||
|
|
||||||
|
arraylist_free(&arraylist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arraylist_at_negative(void)
|
static void test_arraylist_at_negative(void)
|
||||||
@ -420,6 +422,8 @@ static void test_arraylist_at_negative(void)
|
|||||||
|
|
||||||
p_int = arraylist->at(arraylist, -1);
|
p_int = arraylist->at(arraylist, -1);
|
||||||
TEST_ASSERT_EQUAL_INT(10, *p_int);
|
TEST_ASSERT_EQUAL_INT(10, *p_int);
|
||||||
|
|
||||||
|
arraylist_free(&arraylist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arraylist_at_invalid(void)
|
static void test_arraylist_at_invalid(void)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user