写了个取剩余可用堆内存的函数

2022-12-18 0 378

基本原理是湖肚搜寻, 急速malloc, 找出两个malloc(n)成功, malloc(n+1)失败的边线

假如堆内部空间不已连续, 回到的假如是最小已连续内部空间.

流程如下表所示, get_free_mem()中初始化__get_free_mem()时选定上上界.

static size_t __get_free_mem(size_t start, size_t end) { unsigned char *p; size_t size = (start + end) / 2; if(start == end 1) return start 1; p = malloc(size); if(p != NULL) { // malloc succeeded free(p); return __get_free_mem(size + 1, end); } else { // malloc failed return __get_free_mem(start, size); } } size_t get_free_mem(void) { return __get_free_mem(0, 65536UL); }

主要问题有两个, 一是在64k范围时要递归十几次, 4G范围时得递归30多次. 假如初始化边线比较深总担心要爆栈, 得改成非递归的;

二是stm32的syscall.c里的_sbrk()实现是判断heap_end加上incr是否超过asm(“SP”),

其中heap_end是静态变量, 第一次初始化时取_end的值. 这样有个问题是把bss段和当前未用的栈内部空间都给算到堆内部空间了, 似乎不太合适. 是否假如跳过bss段, 以及把整个栈内部空间都去掉?

实测: 在PC上用32位gcc编译, 结果是1.8G左右的缓存. 在512M缓存的树莓派上是345M左右, 都还算合理.

在48k ram的stm32f103rct6上则比较有趣, make完size的结果是.data+.bss一共10256字节,

49152-10256=38896, 再去掉已用掉的栈内部空间, 假如是38k不到的样子. 但是get_free_mem的结果总是32768.

假如先malloc(16000), get_free_mem的结果就变成了16384. 继续malloc, 结果逐渐减小为8192, 4096. 估计是arm-none-eabi-gcc的malloc内部实现上做了限制, 只取需用堆内部空间里最小的2的整数次幂.

假如先这样:

p = malloc(12000); q = malloc(12000); r = malloc(11300); s = malloc(11000);

这样可以成功分配到46300字节, 看来确实是把bss都算进来了. 然后, 果然hardfault了…

上面两点有空再改吧.

—————-更新——————–

上面的说法有误,arm-none-eabi-size -A main_rom.elf的结果, .bss是1860, ._user_heap_stack是8192. 而arm-none-eabi-size -B main_rom.elf的结果, bss是10052,假如是把上面两者都算作bss了。

_user_heap_stack这部分作为堆内部空间是没有问题的,它假如只是在编译时起到检查静态内部空间是否越界的作用。

——————–再更新———————

非递归版本的__get_free_mem表达式如下表所示… 脑子短路了,这个感觉比递归的还简单…

static size_t __get_free_mem2(size_t start, size_t end) { unsigned char *p; while(start < end 1) { size_t size = (start + end) / 2; if(size == 0) return 0; p = malloc(size); if(p != NULL) { // malloc succeeded free(p); start = size; } else { // malloc failed end = size 1; } } return start; }

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务