memory manager support multi blocks of memory

This commit is contained in:
lixianjing 2021-04-22 14:52:29 +08:00
parent 25e05644cf
commit bec68c3713
12 changed files with 453 additions and 36 deletions

View File

@ -93,7 +93,10 @@ COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_EVENT_RECORDER_PLAYER=1 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_ASSET_LOADER -DWITH_FS_RES -DWITH_ASSET_LOADER_ZIP '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DSTBTT_STATIC -DSTB_IMAGE_STATIC -DWITH_STB_IMAGE '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_VGCANVAS -DWITH_UNICODE_BREAK -DWITH_DESKTOP_STYLE '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DHAS_STD_MALLOC -DWITH_SDL -DHAS_STDIO -DHAVE_STDIO_H -DHAS_GET_TIME_US64 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_SDL -DHAS_STDIO -DHAVE_STDIO_H -DHAS_GET_TIME_US64 '
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DHAS_STD_MALLOC -DTK_MAX_MEM_BLOCK_NR=3 '
#COMMON_CCFLAGS=COMMON_CCFLAGS+' -DTK_MAX_MEM_BLOCK_NR=3 '
GRAPHIC_BUFFER='default'

View File

@ -87,6 +87,7 @@
* [如何使用 packed 图](how_to_use_packed_image.md)
* [如何根据实际分辨率自动调整窗口中子控件的位置大小](how_to_auto_scale_children.md)
* [如何修改 stb\_truetype 获取字模时申请的缓冲区大小](how_to_modify_stb_truetype_buffer_size.md)
* [如何让内存管理器支持管理多块不连续的内存](how_to_support_multi_mem_block.md)
### 3. 内部原理
* [AWTK 脚本绑定原理](script_binding.md)

View File

@ -1,5 +1,9 @@
# 最新动态
2021/04/22
* 修改内存泄漏问题。
* 内存管理器支持管理多块不连续的内存。
2021/04/20
* 完善progress cirle demo感谢雨欣提供补丁
* 添加 获取光标位置 接口(感谢兆坤提供补丁)

View File

@ -0,0 +1,41 @@
# AWTK 内存分配器支持多块不连续的内存。
在嵌入式系统中可能有多块不连续的内存。AWTK 最新版本支持管理多个不连续的内存块。使用方法如下:
* 定义内存块数目
> 在 awtk\_config.h 中定义:
```c
#define TK_MAX_MEM_BLOCK_NR 3
```
* 初始化内存
> 需要使用 tk\_mem\_init\_ex 代替 tk\_mem\_init 初始化内存。一般将大块放到前面,小块放到后面。也可以将速度快的内存放到前面,将速度慢的放到后面。
```c
/**
* @method tk_mem_init_ex
* @export none
* 初始化内存,支持多块不连续的内存。
* >最后一个参数必须为NULL。
*
* 示例:
* ```c
* tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL);
* ```
*
* @param {void*} buffer 内存地址。
* @param {uint32_t} size 内存长度。
*
* @return {ret_t} 返回RET_OK表示成功否则表示失败。
*/
ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...);
```
示例:
```c
tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL);
```

View File

@ -235,4 +235,10 @@
* #define WITH_LCD_CLEAR_ALPHA 1
*/
/**
*
*
* #define TK_MAX_MEM_BLOCK_NR 4
*/
#endif /*AWTK_CONFIG_H*/

View File

@ -193,15 +193,14 @@ void sleep_ms(uint32_t ms) {
#endif
}
#ifndef HAS_STD_MALLOC
static uint32_t s_heap_mem[3 * 1024 * 1024];
#endif /*HAS_STD_MALLOC*/
ret_t platform_prepare(void) {
stm_time_init();
#ifndef HAS_STD_MALLOC
tk_mem_init(s_heap_mem, sizeof(s_heap_mem));
static uint32_t s_heap_mem1[10 * 1024];
static uint32_t s_heap_mem2[1 * 1024 * 1024];
static uint32_t s_heap_mem3[3 * 1024 * 1024];
tk_mem_init_ex(s_heap_mem1, sizeof(s_heap_mem1), s_heap_mem2, sizeof(s_heap_mem2), s_heap_mem3, sizeof(s_heap_mem3),NULL);
#endif /*HAS_STD_MALLOC*/
date_time_global_init_ex(&s_date_time_vtable);

View File

@ -19,6 +19,7 @@
*
*/
#include <stdarg.h>
#include "tkc/mem.h"
#include "tkc/time_now.h"
#include "tkc/mem_allocator_oom.h"
@ -69,28 +70,25 @@ ret_t tk_mem_init_stage2(void) {
#else /*non std memory manager*/
#include "tkc/mem_allocator_lock.h"
#include "tkc/mem_allocator_simple.h"
#include "tkc/mem_allocator_composite.h"
static mem_allocator_lock_t s_lock;
static void* s_heap_start = NULL;
static uint32_t s_heap_size = 0;
static mem_allocator_pool_t pool;
static mem_allocator_composite_t composite;
bool_t tk_mem_is_valid_addr(void* addr) {
uint64_t start = (uint64_t)s_heap_start;
uint64_t end = start + s_heap_size;
return (((uint64_t)addr >= (uint64_t)start) && ((uint64_t)addr < end));
return mem_allocator_composite_is_valid_addr(MEM_ALLOCATOR(&composite), addr);
}
ret_t tk_mem_init(void* buffer, uint32_t size) {
static mem_allocator_simple_t simple;
static mem_allocator_pool_t pool;
ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...) {
va_list va;
va_start(va, size);
s_allocator = mem_allocator_composite_init_va(&composite, buffer, size, va);
va_end(va);
s_heap_size = size;
s_heap_start = buffer;
return_value_if_fail(s_allocator != NULL, RET_BAD_PARAMS);
s_allocator = mem_allocator_simple_init(&simple, buffer, size);
if (size < 100 * 1024) {
s_allocator = mem_allocator_pool_init(&pool, s_allocator, 100, 100, 80, 80, 32);
} else if (size < 1000 * 1024) {
@ -105,6 +103,10 @@ ret_t tk_mem_init(void* buffer, uint32_t size) {
return s_allocator != NULL ? RET_OK : RET_FAIL;
}
ret_t tk_mem_init(void* buffer, uint32_t size) {
return tk_mem_init_ex(buffer, size, NULL, 0);
}
ret_t tk_mem_init_stage2(void) {
return_value_if_fail(s_allocator != NULL, RET_FAIL);
s_allocator = mem_allocator_lock_init(&s_lock, s_allocator);

View File

@ -140,6 +140,24 @@ void tk_mem_dump(void);
*/
ret_t tk_mem_init(void* buffer, uint32_t size);
/**
* @method tk_mem_init_ex
* @export none
*
* >NULL
*
*
* ```c
* tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL);
* ```
*
* @param {void*} buffer
* @param {uint32_t} size
*
* @return {ret_t} RET_OK表示成功
*/
ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...);
/**
* @method tk_mem_init_stage2
* @export none

View File

@ -0,0 +1,226 @@
/**
* File: mem_allocator_composite.h
* Author: AWTK Develop Team
* Brief: mem_allocator_composite
*
* Copyright (c) 2020 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2021-04-22 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_MEM_ALLOCATOR_COMPOSITE_H
#define TK_MEM_ALLOCATOR_COMPOSITE_H
#include "tkc/mutex.h"
#include "tkc/mem_allocator_simple.h"
BEGIN_C_DECLS
/*最多支持的内存块数目*/
#ifndef TK_MAX_MEM_BLOCK_NR
#define TK_MAX_MEM_BLOCK_NR 1
#endif /*TK_MAX_MEM_BLOCK_NR*/
/**
* @class mem_allocator_composite_t
* @parent mem_allocator_t
*
*
*
*/
typedef struct _mem_allocator_composite_t {
mem_allocator_t allocator;
mem_allocator_simple_t allocators[TK_MAX_MEM_BLOCK_NR];
} mem_allocator_composite_t;
#define MEM_ALLOCATOR_COMPOSITE(allocator) ((mem_allocator_composite_t*)(allocator))
static inline void* mem_allocator_composite_alloc(mem_allocator_t* allocator, uint32_t size,
const char* func, uint32_t line) {
uint32_t i = 0;
void* addr = NULL;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (mem_allocator_simple_is_valid(iter)) {
addr = mem_allocator_alloc(iter, size, func, line);
if (addr != NULL) {
return addr;
}
}
}
return NULL;
}
static inline bool_t mem_allocator_composite_is_valid_addr(mem_allocator_t* allocator, void* ptr) {
uint32_t i = 0;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (mem_allocator_simple_contains(iter, ptr)) {
return TRUE;
}
}
return FALSE;
}
static inline void mem_allocator_composite_free(mem_allocator_t* allocator, void* ptr) {
uint32_t i = 0;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (mem_allocator_simple_contains(iter, ptr)) {
mem_allocator_free(iter, ptr);
break;
}
}
return;
}
static inline void* mem_allocator_composite_realloc(mem_allocator_t* allocator, void* ptr,
uint32_t size, const char* func,
uint32_t line) {
uint32_t i = 0;
void* addr = NULL;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
if (ptr == NULL) {
return mem_allocator_composite_alloc(allocator, size, func, line);
}
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (mem_allocator_simple_contains(iter, ptr)) {
addr = mem_allocator_realloc(iter, ptr, size, func, line);
if (addr == NULL) {
uint32_t old_size = mem_allocator_simple_get_mem_size(iter, ptr);
addr = mem_allocator_composite_alloc(allocator, size, func, line);
if (addr != NULL) {
uint32_t data_size = tk_min(old_size, size);
memcpy(addr, ptr, data_size);
mem_allocator_simple_free(iter, ptr);
}
}
break;
}
}
return addr;
}
static inline ret_t mem_allocator_composite_dump(mem_allocator_t* allocator) {
uint32_t i = 0;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (mem_allocator_simple_is_valid(iter)) {
mem_allocator_dump(iter);
}
}
return RET_OK;
}
static inline ret_t mem_allocator_composite_destroy(mem_allocator_t* allocator) {
uint32_t i = 0;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (mem_allocator_simple_is_valid(iter)) {
mem_allocator_destroy(iter);
}
}
allocator->vt = NULL;
return RET_OK;
}
static const mem_allocator_vtable_t s_mem_allocator_composite_vtable = {
.alloc = mem_allocator_composite_alloc,
.realloc = mem_allocator_composite_realloc,
.free = mem_allocator_composite_free,
.dump = mem_allocator_composite_dump,
.destroy = mem_allocator_composite_destroy};
static inline ret_t mem_allocator_composite_add_mem(mem_allocator_t* allocator, char* addr,
uint32_t size) {
uint32_t i = 0;
mem_allocator_composite_t* impl = MEM_ALLOCATOR_COMPOSITE(allocator);
for (i = 0; i < ARRAY_SIZE(impl->allocators); i++) {
mem_allocator_t* iter = MEM_ALLOCATOR(impl->allocators + i);
if (!mem_allocator_simple_is_valid(iter)) {
mem_allocator_simple_init(MEM_ALLOCATOR_SIMPLE(iter), addr, size);
log_debug("add mem block %p %u\n", addr, size);
return RET_OK;
}
}
log_warn("no space to add mem, please increase TK_MAX_MEM_BLOCK_NR\n");
return RET_BAD_PARAMS;
}
static inline mem_allocator_t* mem_allocator_composite_init_va(mem_allocator_composite_t* composite,
void* buffer, uint32_t size,
va_list va) {
char* p = NULL;
mem_allocator_t* allocator = MEM_ALLOCATOR(composite);
return_value_if_fail(composite != NULL, NULL);
memset(composite, 0x00, sizeof(*composite));
allocator->vt = &s_mem_allocator_composite_vtable;
ENSURE(mem_allocator_composite_add_mem(allocator, buffer, size) == RET_OK);
do {
p = va_arg(va, char*);
if (p != NULL) {
uint32_t s = va_arg(va, uint32_t);
ENSURE(mem_allocator_composite_add_mem(allocator, p, s) == RET_OK);
}
} while (p != NULL);
return allocator;
}
static inline mem_allocator_t* mem_allocator_composite_init(mem_allocator_composite_t* composite,
void* buffer, uint32_t size, ...) {
va_list va;
mem_allocator_t* ret = NULL;
va_start(va, size);
ret = mem_allocator_composite_init_va(composite, buffer, size, va);
va_end(va);
return ret;
}
END_C_DECLS
#endif /*TK_MEM_ALLOCATOR_COMPOSITE_H*/

View File

@ -74,11 +74,9 @@ static void* tk_alloc_impl(mem_allocator_t* allocator, uint32_t s) {
}
if (iter == NULL) {
log_debug("%s: Out of memory(%d):\n", __FUNCTION__, (int)size);
return NULL;
}
return_value_if_fail(iter != NULL, NULL);
/*如果找到的空闲块刚好满足需求,就从空闲块链表中移出它*/
if (iter->size < (size + MIN_SIZE)) {
if (info->free_list == iter) {
@ -262,6 +260,19 @@ static inline void mem_allocator_simple_free(mem_allocator_t* allocator, void* p
tk_free_impl(allocator, ptr);
}
static inline bool_t mem_allocator_simple_is_valid(mem_allocator_t* allocator) {
mem_info_t* info = &(MEM_ALLOCATOR_SIMPLE(allocator)->info);
return info->buffer != NULL && info->size > 0;
}
static inline bool_t mem_allocator_simple_contains(mem_allocator_t* allocator, void* ptr) {
char* p = (char*)ptr;
mem_info_t* info = &(MEM_ALLOCATOR_SIMPLE(allocator)->info);
return (p >= info->buffer && (p - info->buffer) < info->size);
}
static inline ret_t mem_allocator_simple_dump(mem_allocator_t* allocator) {
mem_info_t* info = &(MEM_ALLOCATOR_SIMPLE(allocator)->info);
log_debug("used: %u(max=%u) bytes %u(max=%u) blocks\n", info->used_bytes, info->used_max_bytes,
@ -271,6 +282,16 @@ static inline ret_t mem_allocator_simple_dump(mem_allocator_t* allocator) {
return RET_OK;
}
static uint32_t mem_allocator_simple_get_mem_size(mem_allocator_t* allocator, void* ptr) {
free_node_t* free_iter = NULL;
return_value_if_fail(ptr != NULL, 0);
free_iter = (free_node_t*)((char*)ptr - sizeof(uint32_t));
return free_iter->size;
}
static inline ret_t mem_allocator_simple_destroy(mem_allocator_t* allocator) {
allocator->vt = NULL;
return RET_OK;

View File

@ -29,7 +29,6 @@ SOURCES = [
] + Glob('*.cc') + Glob('*.c')
env.Program(os.path.join(BIN_DIR, 'runTest'), SOURCES);
#env.Program(os.path.join(BIN_DIR, 'mem_test'), ["mem_test.cpp"])
env.Program(os.path.join(BIN_DIR, 'recycle_test'), ["recycle_test.cpp"])
env.Program(os.path.join(BIN_DIR, 'waitable_action_queue_test'), ["waitable_action_queue_test.cpp"])
env.Program(os.path.join(BIN_DIR, 'waitable_ring_buffer_test'), ["waitable_ring_buffer_test.cpp"])

View File

@ -1,15 +1,13 @@
#include "tkc/mem_allocator_pool.h"
#include "tkc/mem.h"
#include "tkc/mem_allocator_pool.h"
#include "tkc/mem_allocator_simple.h"
void allocator_test_basic() {
#include "tkc/mem_allocator_composite.h"
void allocator_test_basic_ex(mem_allocator_t* allocator) {
uint32_t i = 0;
char buff[102400];
void* addr = NULL;
void* addrs[100];
mem_allocator_simple_t simple;
mem_allocator_pool_t pool;
mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff));
allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10);
for (i = 0; i < ARRAY_SIZE(addrs); i++) {
addr = mem_allocator_alloc(allocator, i + 1, __FUNCTION__, __LINE__);
@ -25,21 +23,31 @@ void allocator_test_basic() {
mem_allocator_free(allocator, addrs[i]);
}
}
void allocator_test_basic() {
uint32_t i = 0;
char buff[102400];
mem_allocator_simple_t simple;
mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff));
mem_allocator_pool_t pool;
allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10);
allocator_test_basic_ex(allocator);
for (i = 0; i < TK_MEM_POOLS_NR; i++) {
assert(pool.pools[i]->used == 0);
}
mem_allocator_destroy(allocator);
return;
}
void allocator_test_rand() {
void allocator_test_rand_ex(mem_allocator_t* allocator) {
uint32_t k = 0;
uint32_t i = 0;
char buff[1000 * 1000];
void* addr = NULL;
void* addrs[1000];
mem_allocator_simple_t simple;
mem_allocator_pool_t pool;
mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff));
allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10);
for (k = 0; k < 1000; k++) {
for (i = 0; i < ARRAY_SIZE(addrs); i++) {
@ -57,12 +65,101 @@ void allocator_test_rand() {
mem_allocator_free(allocator, addrs[i]);
}
}
}
void allocator_test_rand() {
uint32_t i = 0;
char buff[1000 * 1000];
mem_allocator_simple_t simple;
mem_allocator_t* allocator = mem_allocator_simple_init(&simple, buff, sizeof(buff));
mem_allocator_pool_t pool;
allocator = mem_allocator_pool_init(&pool, allocator, 10, 10, 10, 10, 10);
allocator_test_rand_ex(allocator);
for (i = 0; i < TK_MEM_POOLS_NR; i++) {
assert(pool.pools[i]->used == 0);
}
mem_allocator_destroy(allocator);
}
void allocator_test_composite0() {
char mem1[100*1000];
char mem2[1000*1000];
char* addr = NULL;
mem_allocator_composite_t composite;
mem_allocator_t* allocator = mem_allocator_composite_init(&composite, mem1, sizeof(mem1), mem2, sizeof(mem2), NULL);
allocator_test_basic_ex(allocator);
allocator_test_rand_ex(allocator);
mem_allocator_destroy(allocator);
}
void allocator_test_composite1() {
char mem1[36];
char mem2[64];
char mem3[1280];
char* addr = NULL;
mem_allocator_composite_t composite;
mem_allocator_t* allocator = mem_allocator_composite_init(&composite, mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL);
/*mem1*/
addr = mem_allocator_alloc(allocator, 16, __FUNCTION__, __LINE__);
assert(addr >= mem1);
assert(addr < (mem1 + sizeof(mem1)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
mem_allocator_free(allocator, addr);
addr = mem_allocator_alloc(allocator, 16, __FUNCTION__, __LINE__);
assert(addr >= mem1);
assert(addr < (mem1 + sizeof(mem1)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
addr = mem_allocator_realloc(allocator, addr, 16+2, __FUNCTION__, __LINE__);
assert(addr >= mem1);
assert(addr < (mem1 + sizeof(mem1)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
/*mem2*/
addr = mem_allocator_alloc(allocator, 36, __FUNCTION__, __LINE__);
assert(addr >= mem2);
assert(addr < (mem2 + sizeof(mem2)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
mem_allocator_free(allocator, addr);
addr = mem_allocator_alloc(allocator, 36, __FUNCTION__, __LINE__);
assert(addr >= mem2);
assert(addr < (mem2 + sizeof(mem2)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
addr = mem_allocator_realloc(allocator, addr, 30, __FUNCTION__, __LINE__);
assert(addr >= mem2);
assert(addr < (mem2 + sizeof(mem2)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
/*mem3*/
addr = mem_allocator_alloc(allocator, 66, __FUNCTION__, __LINE__);
assert(addr >= mem3);
assert(addr < (mem3 + sizeof(mem3)));
mem_allocator_free(allocator, addr);
addr = mem_allocator_alloc(allocator, 66, __FUNCTION__, __LINE__);
assert(addr >= mem3);
assert(addr < (mem3 + sizeof(mem3)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
addr = mem_allocator_realloc(allocator, addr, 66+2, __FUNCTION__, __LINE__);
assert(addr >= mem3);
assert(addr < (mem3 + sizeof(mem3)));
assert(mem_allocator_composite_is_valid_addr(allocator, addr));
mem_allocator_destroy(allocator);
return;
}
void allocator_test() {
allocator_test_composite1();
allocator_test_basic();
allocator_test_rand();
}